From b50187f59c09d4ecf7a840fd22f96bcecd14bb1b Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Tue, 27 Nov 2018 11:25:51 -0800
Subject: Track install wallet clicked

---
 .../containers/connected_account_payment_method.ts | 37 ++++++++++++----------
 packages/instant/src/types.ts                      |  5 +++
 packages/instant/src/util/analytics.ts             |  5 ++-
 3 files changed, 30 insertions(+), 17 deletions(-)

diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts
index cdeb49a25..e9327a288 100644
--- a/packages/instant/src/containers/connected_account_payment_method.ts
+++ b/packages/instant/src/containers/connected_account_payment_method.ts
@@ -11,7 +11,7 @@ import {
 import { Action, actions } from '../redux/actions';
 import { asyncData } from '../redux/async_data';
 import { State } from '../redux/reducer';
-import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent } from '../types';
+import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent, WalletSuggestion } from '../types';
 import { analytics } from '../util/analytics';
 import { envUtil } from '../util/env';
 
@@ -60,23 +60,28 @@ const mergeProps = (
     onUnlockWalletClick: () => connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState),
     onInstallWalletClick: () => {
         const isMobile = envUtil.isMobileOperatingSystem();
-        if (!isMobile) {
+        const walletSuggestion: WalletSuggestion = isMobile
+            ? WalletSuggestion.CoinbaseWallet
+            : WalletSuggestion.MetaMask;
+
+        analytics.trackInstallWalletClicked(walletSuggestion);
+        if (walletSuggestion === WalletSuggestion.MetaMask) {
             connectedDispatch.openInstallWalletPanel();
-            return;
-        }
-        const operatingSystem = envUtil.getOperatingSystem();
-        let url = COINBASE_WALLET_SITE_URL;
-        switch (operatingSystem) {
-            case OperatingSystem.Android:
-                url = COINBASE_WALLET_ANDROID_APP_STORE_URL;
-                break;
-            case OperatingSystem.iOS:
-                url = COINBASE_WALLET_IOS_APP_STORE_URL;
-                break;
-            default:
-                break;
+        } else {
+            const operatingSystem = envUtil.getOperatingSystem();
+            let url = COINBASE_WALLET_SITE_URL;
+            switch (operatingSystem) {
+                case OperatingSystem.Android:
+                    url = COINBASE_WALLET_ANDROID_APP_STORE_URL;
+                    break;
+                case OperatingSystem.iOS:
+                    url = COINBASE_WALLET_IOS_APP_STORE_URL;
+                    break;
+                default:
+                    break;
+            }
+            window.open(url, '_blank');
         }
-        window.open(url, '_blank');
     },
 });
 
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index 999d50fed..4ad9c9d4f 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -149,6 +149,11 @@ export enum Browser {
     Other = 'OTHER',
 }
 
+export enum WalletSuggestion {
+    CoinbaseWallet = 'Coinbase Wallet',
+    MetaMask = 'MetaMask',
+}
+
 export enum OperatingSystem {
     Android = 'ANDROID',
     iOS = 'IOS',
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index 2bb974254..e35a9e13f 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -1,7 +1,7 @@
 import { BuyQuote } from '@0x/asset-buyer';
 import * as _ from 'lodash';
 
-import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types';
+import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, WalletSuggestion } from '../types';
 
 import { EventProperties, heapUtil } from './heap';
 
@@ -30,6 +30,7 @@ enum EventNames {
     BUY_TX_SUBMITTED = 'Buy - Tx Submitted',
     BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded',
     BUY_TX_FAILED = 'Buy - Tx Failed',
+    INSTALL_WALLET_CLICKED = 'Install Wallet - Clicked',
     TOKEN_SELECTOR_OPENED = 'Token Selector - Opened',
     TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed',
     TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose',
@@ -164,6 +165,8 @@ export const analytics = {
             expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
             actualTxTimeMs: new Date().getTime() - startTimeUnix,
         }),
+    trackInstallWalletClicked: (walletSuggestion: WalletSuggestion) =>
+        trackingEventFnWithPayload(EventNames.INSTALL_WALLET_CLICKED)({ walletSuggestion }),
     trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED),
     trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) =>
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }),
-- 
cgit v1.2.3


From 462a5face9b2b24c1e9d20a6b894809faa512232 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Tue, 27 Nov 2018 13:30:28 -0800
Subject: feat(instant): Install Wallet analytics

---
 .../src/components/install_wallet_panel_content.tsx        |  9 ++++++++-
 packages/instant/src/components/standard_panel_content.tsx | 13 ++++++++++++-
 packages/instant/src/redux/analytics_middleware.ts         | 14 +++++++++++++-
 packages/instant/src/util/analytics.ts                     | 10 ++++++++++
 4 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/packages/instant/src/components/install_wallet_panel_content.tsx b/packages/instant/src/components/install_wallet_panel_content.tsx
index 88c26f59c..481d82da0 100644
--- a/packages/instant/src/components/install_wallet_panel_content.tsx
+++ b/packages/instant/src/components/install_wallet_panel_content.tsx
@@ -8,7 +8,9 @@ import {
 } from '../constants';
 import { ColorOption } from '../style/theme';
 import { Browser } from '../types';
+import { analytics } from '../util/analytics';
 import { envUtil } from '../util/env';
+import { util } from '../util/util';
 
 import { MetaMaskLogo } from './meta_mask_logo';
 import { StandardPanelContent, StandardPanelContentProps } from './standard_panel_content';
@@ -45,6 +47,10 @@ export class InstallWalletPanelContent extends React.Component<InstallWalletPane
             default:
                 break;
         }
+        const onActionClick = () => {
+            analytics.trackInstallWalletModalClickedGet();
+            util.createOpenUrlInNewWindow(actionUrl)();
+        };
         return {
             image: <MetaMaskLogo width={85} height={80} />,
             title: 'Install MetaMask',
@@ -52,10 +58,11 @@ export class InstallWalletPanelContent extends React.Component<InstallWalletPane
             moreInfoSettings: {
                 href: META_MASK_SITE_URL,
                 text: 'What is MetaMask?',
+                onClick: analytics.trackInstallWalletModalClickedExplanation,
             },
             action: (
                 <Button
-                    href={actionUrl}
+                    onClick={onActionClick}
                     width="100%"
                     fontColor={ColorOption.white}
                     backgroundColor={ColorOption.darkOrange}
diff --git a/packages/instant/src/components/standard_panel_content.tsx b/packages/instant/src/components/standard_panel_content.tsx
index 582b3318e..79b7bff24 100644
--- a/packages/instant/src/components/standard_panel_content.tsx
+++ b/packages/instant/src/components/standard_panel_content.tsx
@@ -1,6 +1,7 @@
 import * as React from 'react';
 
 import { ColorOption } from '../style/theme';
+import { util } from '../util/util';
 
 import { Container } from './ui/container';
 import { Flex } from './ui/flex';
@@ -9,6 +10,7 @@ import { Text } from './ui/text';
 export interface MoreInfoSettings {
     text: string;
     href: string;
+    onClick?: () => void;
 }
 
 export interface StandardPanelContentProps {
@@ -21,6 +23,15 @@ export interface StandardPanelContentProps {
 
 const SPACING_BETWEEN_PX = '20px';
 
+const onMoreInfoClick = (href: string, onClick?: () => void) => {
+    return () => {
+        if (onClick) {
+            onClick();
+        }
+        util.createOpenUrlInNewWindow(href)();
+    };
+};
+
 export const StandardPanelContent: React.StatelessComponent<StandardPanelContentProps> = ({
     image,
     title,
@@ -50,7 +61,7 @@ export const StandardPanelContent: React.StatelessComponent<StandardPanelContent
                         fontSize="13px"
                         textDecorationLine="underline"
                         fontColor={ColorOption.lightGrey}
-                        href={moreInfoSettings.href}
+                        onClick={onMoreInfoClick(moreInfoSettings.href, moreInfoSettings.onClick)}
                     >
                         {moreInfoSettings.text}
                     </Text>
diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts
index 8aa76eb77..3dc5fe924 100644
--- a/packages/instant/src/redux/analytics_middleware.ts
+++ b/packages/instant/src/redux/analytics_middleware.ts
@@ -3,7 +3,7 @@ import * as _ from 'lodash';
 import { Middleware } from 'redux';
 
 import { ETH_DECIMALS } from '../constants';
-import { Account, AccountState } from '../types';
+import { Account, AccountState, StandardSlidingPanelContent } from '../types';
 import { analytics } from '../util/analytics';
 
 import { Action, ActionTypes } from './actions';
@@ -77,6 +77,18 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction
                 });
             }
             break;
+        case ActionTypes.OPEN_STANDARD_SLIDING_PANEL:
+            const openSlidingContent = curState.standardSlidingPanelSettings.content;
+            if (openSlidingContent === StandardSlidingPanelContent.InstallWallet) {
+                analytics.trackInstallWalletModalOpened();
+            }
+            break;
+        case ActionTypes.CLOSE_STANDARD_SLIDING_PANEL:
+            const closeSlidingContent = curState.standardSlidingPanelSettings.content;
+            if (closeSlidingContent === StandardSlidingPanelContent.InstallWallet) {
+                analytics.trackInstallWalletModalClosed();
+            }
+            break;
     }
 
     return nextAction;
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index e35a9e13f..f1ce15805 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -31,6 +31,10 @@ enum EventNames {
     BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded',
     BUY_TX_FAILED = 'Buy - Tx Failed',
     INSTALL_WALLET_CLICKED = 'Install Wallet - Clicked',
+    INSTALL_WALLET_MODAL_OPENED = 'Install Wallet - Modal - Opened',
+    INSTALL_WALLET_MODAL_CLICKED_EXPLANATION = 'Install Wallet - Modal - Clicked Explanation',
+    INSTALL_WALLET_MODAL_CLICKED_GET = 'Install Wallet - Modal - Clicked Get',
+    INSTALL_WALLET_MODAL_CLOSED = 'Install Wallet - Modal - Closed',
     TOKEN_SELECTOR_OPENED = 'Token Selector - Opened',
     TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed',
     TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose',
@@ -167,6 +171,12 @@ export const analytics = {
         }),
     trackInstallWalletClicked: (walletSuggestion: WalletSuggestion) =>
         trackingEventFnWithPayload(EventNames.INSTALL_WALLET_CLICKED)({ walletSuggestion }),
+    trackInstallWalletModalClickedExplanation: trackingEventFnWithoutPayload(
+        EventNames.INSTALL_WALLET_MODAL_CLICKED_EXPLANATION,
+    ),
+    trackInstallWalletModalClickedGet: trackingEventFnWithoutPayload(EventNames.INSTALL_WALLET_MODAL_CLICKED_GET),
+    trackInstallWalletModalOpened: trackingEventFnWithoutPayload(EventNames.INSTALL_WALLET_MODAL_OPENED),
+    trackInstallWalletModalClosed: trackingEventFnWithoutPayload(EventNames.INSTALL_WALLET_MODAL_CLOSED),
     trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED),
     trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) =>
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }),
-- 
cgit v1.2.3


From c5d6b925e4e04d5b6cfd0623d0a1449ba69d3a30 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Tue, 27 Nov 2018 15:10:40 -0800
Subject: feat(instant): Quote fetch tracking

---
 packages/instant/src/components/zero_ex_instant_provider.tsx  |  7 +++++--
 .../src/containers/selected_erc20_asset_amount_input.ts       |  3 ++-
 packages/instant/src/redux/async_data.ts                      | 11 ++++++++---
 packages/instant/src/types.ts                                 |  5 +++++
 packages/instant/src/util/analytics.ts                        |  9 ++++++++-
 packages/instant/src/util/buy_quote_updater.ts                | 11 +++++++++--
 packages/instant/src/util/heartbeater_factory.ts              |  2 ++
 7 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index e006a5a5f..9f2c95e36 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -11,7 +11,7 @@ import { asyncData } from '../redux/async_data';
 import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer';
 import { store, Store } from '../redux/store';
 import { fonts } from '../style/fonts';
-import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types';
+import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchedVia } from '../types';
 import { analytics, disableAnalytics } from '../util/analytics';
 import { assetUtils } from '../util/asset';
 import { errorFlasher } from '../util/error_flasher';
@@ -115,7 +115,10 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
         this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS);
         // Trigger first buyquote fetch
         // tslint:disable-next-line:no-floating-promises
-        asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, { updateSilently: false });
+        asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, {
+            updateSilently: false,
+            fetchedVia: QuoteFetchedVia.Manual,
+        });
         // warm up the gas price estimator cache just in case we can't
         // grab the gas price estimate when submitting the transaction
         // tslint:disable-next-line:no-floating-promises
diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
index a39bc46a2..1e9b22617 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -10,7 +10,7 @@ import { ERC20AssetAmountInput, ERC20AssetAmountInputProps } from '../components
 import { Action, actions } from '../redux/actions';
 import { State } from '../redux/reducer';
 import { ColorOption } from '../style/theme';
-import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState } from '../types';
+import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState, QuoteFetchedVia } from '../types';
 import { buyQuoteUpdater } from '../util/buy_quote_updater';
 
 export interface SelectedERC20AssetAmountInputProps {
@@ -92,6 +92,7 @@ const mapDispatchToProps = (
                 setPending: true,
                 dispatchErrors: true,
                 affiliateInfo,
+                fetchedVia: QuoteFetchedVia.Manual,
             });
         }
     },
diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts
index 6feb760e7..2efc3698f 100644
--- a/packages/instant/src/redux/async_data.ts
+++ b/packages/instant/src/redux/async_data.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 import { Dispatch } from 'redux';
 
 import { BIG_NUMBER_ZERO } from '../constants';
-import { AccountState, ERC20Asset, OrderProcessState, ProviderState } from '../types';
+import { AccountState, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchedVia } from '../types';
 import { analytics } from '../util/analytics';
 import { assetUtils } from '../util/asset';
 import { buyQuoteUpdater } from '../util/buy_quote_updater';
@@ -84,7 +84,7 @@ export const asyncData = {
     fetchCurrentBuyQuoteAndDispatchToStore: async (
         state: State,
         dispatch: Dispatch,
-        options: { updateSilently: boolean },
+        options: { updateSilently: boolean; fetchedVia: QuoteFetchedVia },
     ) => {
         const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
         const assetBuyer = providerState.assetBuyer;
@@ -99,7 +99,12 @@ export const asyncData = {
                 dispatch,
                 selectedAsset as ERC20Asset,
                 selectedAssetUnitAmount,
-                { setPending: !options.updateSilently, dispatchErrors: !options.updateSilently, affiliateInfo },
+                {
+                    setPending: !options.updateSilently,
+                    dispatchErrors: !options.updateSilently,
+                    fetchedVia: options.fetchedVia,
+                    affiliateInfo,
+                },
             );
         }
     },
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index 999d50fed..a8139c185 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -21,6 +21,11 @@ export enum OrderProcessState {
     Failure = 'FAILURE',
 }
 
+export enum QuoteFetchedVia {
+    Manual = 'Manual',
+    Heartbeat = 'Heartbeat',
+}
+
 export interface SimulatedProgress {
     startTimeUnix: number;
     expectedEndTimeUnix: number;
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index 5bc9bb385..204b6921d 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -1,7 +1,7 @@
 import { BuyQuote } from '@0x/asset-buyer';
 import * as _ from 'lodash';
 
-import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types';
+import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchedVia } from '../types';
 
 import { EventProperties, heapUtil } from './heap';
 
@@ -37,6 +37,8 @@ enum EventNames {
     TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed',
     TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose',
     TOKEN_SELECTOR_SEARCHED = 'Token Selector - Searched',
+    QUOTE_FETCHED = 'Quote - Fetched',
+    QUOTE_ERROR = 'Quote - Error',
 }
 
 const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => {
@@ -177,4 +179,9 @@ export const analytics = {
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload),
     trackTokenSelectorSearched: (searchText: string) =>
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }),
+    trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchedVia) =>
+        trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({
+            ...buyQuoteEventProperties(buyQuote),
+            fetchedVia,
+        }),
 };
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 2fd16d781..59d3a85af 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -6,7 +6,8 @@ import { Dispatch } from 'redux';
 import { oc } from 'ts-optchain';
 
 import { Action, actions } from '../redux/actions';
-import { AffiliateInfo, ERC20Asset } from '../types';
+import { AffiliateInfo, ERC20Asset, QuoteFetchedVia } from '../types';
+import { analytics } from '../util/analytics';
 import { assetUtils } from '../util/asset';
 import { errorFlasher } from '../util/error_flasher';
 
@@ -16,7 +17,12 @@ export const buyQuoteUpdater = {
         dispatch: Dispatch<Action>,
         asset: ERC20Asset,
         assetUnitAmount: BigNumber,
-        options: { setPending: boolean; dispatchErrors: boolean; affiliateInfo?: AffiliateInfo },
+        options: {
+            setPending: boolean;
+            dispatchErrors: boolean;
+            fetchedVia: QuoteFetchedVia;
+            affiliateInfo?: AffiliateInfo;
+        },
     ): Promise<void> => {
         // get a new buy quote.
         const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetUnitAmount, asset.metaData.decimals);
@@ -58,5 +64,6 @@ export const buyQuoteUpdater = {
         errorFlasher.clearError(dispatch);
         // invalidate the last buy quote.
         dispatch(actions.updateLatestBuyQuote(newBuyQuote));
+        analytics.trackQuoteFetched(newBuyQuote, options.fetchedVia);
     },
 };
diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts
index 2b852fb0d..bf9e4291f 100644
--- a/packages/instant/src/util/heartbeater_factory.ts
+++ b/packages/instant/src/util/heartbeater_factory.ts
@@ -1,5 +1,6 @@
 import { asyncData } from '../redux/async_data';
 import { Store } from '../redux/store';
+import { QuoteFetchedVia } from '../types';
 
 import { Heartbeater } from './heartbeater';
 
@@ -19,6 +20,7 @@ export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): H
     return new Heartbeater(async () => {
         await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, {
             updateSilently: true,
+            fetchedVia: QuoteFetchedVia.Heartbeat,
         });
     }, shouldPerformImmediatelyOnStart);
 };
-- 
cgit v1.2.3


From d3739488aed89ce98e805d48ec14a0d2608f85d7 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Tue, 27 Nov 2018 15:28:38 -0800
Subject: Tracking quote errors

---
 packages/instant/src/util/analytics.ts         | 16 ++++++++++++++++
 packages/instant/src/util/buy_quote_updater.ts |  7 +++++++
 2 files changed, 23 insertions(+)

diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index 204b6921d..dd6021453 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -1,4 +1,5 @@
 import { BuyQuote } from '@0x/asset-buyer';
+import { BigNumber } from '@0x/utils';
 import * as _ from 'lodash';
 
 import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchedVia } from '../types';
@@ -184,4 +185,19 @@ export const analytics = {
             ...buyQuoteEventProperties(buyQuote),
             fetchedVia,
         }),
+    trackQuoteError: (
+        errorMessage: string,
+        assetName: string,
+        assetData: string,
+        assetAmount: BigNumber,
+        fetchedVia: QuoteFetchedVia,
+    ) => {
+        trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({
+            errorMessage,
+            assetName,
+            assetData,
+            assetAmount: assetAmount.toString(),
+            fetchedVia,
+        });
+    },
 };
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 59d3a85af..3c982ed1f 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -37,6 +37,13 @@ export const buyQuoteUpdater = {
         } catch (error) {
             if (options.dispatchErrors) {
                 dispatch(actions.setQuoteRequestStateFailure());
+                analytics.trackQuoteError(
+                    error.message ? error.message : 'other',
+                    asset.metaData.name,
+                    asset.assetData,
+                    assetUnitAmount,
+                    options.fetchedVia,
+                );
                 let errorMessage;
                 if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
                     const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
-- 
cgit v1.2.3


From 8b80d28029c6d840c7401b06a15652523f5faa60 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Wed, 7 Nov 2018 10:32:49 -0800
Subject: feat: Implement MultiAssetProxy

---
 packages/contracts/compiler.json                   |   1 +
 .../protocol/AssetProxy/MultiAssetProxy.sol        | 249 +++++++++++++++++++++
 .../protocol/AssetProxy/interfaces/IAssetData.sol  |  11 +-
 3 files changed, 259 insertions(+), 2 deletions(-)
 create mode 100644 packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol

diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json
index af3980b4e..c824e4645 100644
--- a/packages/contracts/compiler.json
+++ b/packages/contracts/compiler.json
@@ -38,6 +38,7 @@
         "IValidator",
         "IWallet",
         "MixinAuthorizable",
+        "MultiAssetProxy",
         "MultiSigWallet",
         "MultiSigWalletWithTimeLock",
         "OrderValidator",
diff --git a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
new file mode 100644
index 000000000..9260ead8f
--- /dev/null
+++ b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -0,0 +1,249 @@
+/*
+
+  Copyright 2018 ZeroEx Intl.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../utils/SafeMath/SafeMath.sol";
+import "../Exchange/MixinAssetProxyDispatcher.sol";
+import "./MixinAuthorizable.sol";
+
+
+contract MultiAssetProxy is
+    SafeMath,
+    MixinAssetProxyDispatcher,
+    MixinAuthorizable
+{
+    // Id of this proxy.
+    bytes4 constant internal PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],bytes[])"));
+
+    // solhint-disable-next-line payable-fallback
+    function ()
+        external
+    {
+        assembly {
+            // The first 4 bytes of calldata holds the function selector
+            let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
+
+            // `transferFrom` will be called with the following parameters:
+            // assetData Encoded byte array.
+            // from Address to transfer asset from.
+            // to Address to transfer asset to.
+            // amount Amount of asset to transfer.
+            // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
+            if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
+
+                // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
+                // where k is the key left padded to 32 bytes and p is the storage slot
+                mstore(0, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
+                mstore(32, authorized_slot)
+
+                // Revert if authorized[msg.sender] == false
+                if iszero(sload(keccak256(0, 64))) {
+                    // Revert with `Error("SENDER_NOT_AUTHORIZED")`
+                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                    mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
+                    mstore(96, 0)
+                    revert(0, 100)
+                }
+
+                // `transferFrom`.
+                // The function is marked `external`, so no abi decodeding is done for
+                // us. Instead, we expect the `calldata` memory to contain the
+                // following:
+                //
+                // | Area     | Offset | Length  | Contents                            |
+                // |----------|--------|---------|-------------------------------------|
+                // | Header   | 0      | 4       | function selector                   |
+                // | Params   |        | 4 * 32  | function parameters:                |
+                // |          | 4      |         |   1. offset to assetData (*)        |
+                // |          | 36     |         |   2. from                           |
+                // |          | 68     |         |   3. to                             |
+                // |          | 100    |         |   4. amount                         |
+                // | Data     |        |         | assetData:                          |
+                // |          | 132    | 32      | assetData Length                    |
+                // |          | 164    | **      | assetData Contents                  |
+                //
+                // (*): offset is computed from start of function parameters, so offset
+                //      by an additional 4 bytes in the calldata.
+                //
+                // (**): see table below to compute length of assetData Contents
+                //
+                // WARNING: The ABIv2 specification allows additional padding between
+                //          the Params and Data section. This will result in a larger
+                //          offset to assetData.
+
+                // Load offset to `assetData`
+                let assetDataOffset := calldataload(4)
+
+                // Asset data itself is encoded as follows:
+                //
+                // | Area     | Offset      | Length  | Contents                            |
+                // |----------|-------------|---------|-------------------------------------|
+                // | Header   | 0           | 4       | assetProxyId                        |
+                // | Params   |             | 2 * 32  | function parameters:                |
+                // |          | 4           |         |   1. offset to amounts (*)          |
+                // |          | 36          |         |   2. offset to nestedAssetData (*)  |
+                // | Data     |             |         | amounts:                            |
+                // |          | 68          | 32      | amounts Length                      |
+                // |          | 100         | a       | amounts Contents                    | 
+                // |          |             |         | nestedAssetData:                    |
+                // |          | 100 + a     | 32      | nestedAssetData Length              |
+                // |          | 132 + a     | b       | nestedAssetData Contents (offsets)  |
+                // |          | 132 + a + b |         | nestedAssetData[0, ..., len]        |
+
+                // Load offset to `amounts`
+                // We must add 4 (function selector) + 32 (assetData len) + 4 (assetProxyId) to the assetData offset
+                let amountsOffset := calldataload(add(assetDataOffset, 40))
+
+                // Load offsets to `nestedAssetData`
+                let nestedAssetDataOffset := calldataload(add(assetDataOffset, 72))
+
+                // Load number of elements in `amounts`
+                // We must add 4 (function selector) + 128 (4 params * 32) + 32 (assetData len) + 4 (assetProxyId) + 32 (amounts len) to the amounts offset
+                let amountsContentsStart := add(amountsOffset, 200)
+                let amountsLen := calldataload(sub(amountsContentsStart, 32))
+
+                // Load number of elements in `nestedAssetData`
+                let nestedAssetDataContentsStart := add(nestedAssetDataOffset, 200)
+                let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
+
+                // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
+                if iszero(eq(amountsLen, nestedAssetDataLen)) {
+                    // Revert with `Error("LENGTH_MISMATCH")`
+                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                    mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000)
+                    mstore(96, 0)
+                    revert(0, 100)
+                }
+
+                // Copy `transferFrom` selector, offset to `assetData`, `from`, and `to` from calldata to memory
+                calldatacopy(
+                    0,   // memory can safely be overwritten from beginning
+                    0,   // start of calldata
+                    100  // length of selector (4) and 3 params (32 * 3)
+                )
+
+                // Overwrite existing offset to `assetData` with our own
+                mstore(4, 128)
+                
+                // Load `amount`
+                let amount := calldataload(100)
+        
+                // Calculate number of bytes in `amounts` contents
+                let amountsByteLen := mul(amountsLen, 32)
+
+                // Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element
+                for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} {
+
+                    // Calculate the total amount
+                    let amountsElement := calldataload(add(amountsContentsStart, i))
+                    let totalAmount := mul(amountsElement, amount)
+
+                    // Revert if multiplication resulted in an overflow
+                    if iszero(eq(div(totalAmount, amount), amountsElement)) {
+                        // Revert with `Error("UINT256_OVERFLOW")`
+                        mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                        mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                        mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000)
+                        mstore(96, 0)
+                        revert(0, 100)
+                    }
+
+                    // Write `totalAmount` to memory
+                    mstore(100, totalAmount)
+
+                    // Load offset to `nestedAssetData[i]`
+                    let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
+
+                    // Load length of `nestedAssetData[i]`
+                    let nestedAssetDataElementContentsStart := add(nestedAssetDataElementOffset, 264)
+                    let nestedAssetDataElementLen := calldataload(sub(nestedAssetDataElementContentsStart, 32))
+
+                    // Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId`
+                    if lt(nestedAssetDataElementLen, 4) {
+                        // Revert with `Error("LENGTH_GREATER_THAN_3_REQUIRED")`
+                        mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                        mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                        mstore(64, 0x0000001e4c454e4754485f475245415445525f5448414e5f335f524551554952)
+                        mstore(96, 0x4544000000000000000000000000000000000000000000000000000000000000)
+                        revert(0, 100)
+                    }
+
+                    // Load AssetProxy id
+                    let assetProxyId := and(calldataload(nestedAssetDataElementContentsStart), 0xffffffff00000000000000000000000000000000000000000000000000000000)
+
+                    // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
+                    // where k is the key left padded to 32 bytes and p is the storage slot
+                    mstore(132, assetProxyId)
+                    mstore(164, assetProxies_slot)
+                    let assetProxy := sload(keccak256(132, 64))
+                    
+                    // Revert if AssetProxy with given id does not exist
+                    if iszero(assetProxy) {
+                        // Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
+                        mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
+                        mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
+                        mstore(64, 0x0000001a41535345545f50524f58595f444f45535f4e4f545f45584953540000)
+                        mstore(96, 0)
+                        revert(0, 100)
+                    }
+    
+                    // Copy `nestedAssetData[i]` from calldata to memory
+                    calldatacopy(
+                        132,                                // memory slot after `amounts[i]`
+                        nestedAssetDataElementOffset,       // location of `nestedAssetData[i]` in calldata
+                        add(nestedAssetDataElementLen, 32)  // `nestedAssetData[i].length` plus 32 byte length
+                    )
+
+                    // call `assetProxy.transferFrom`
+                    let success := call(
+                        gas,                                    // forward all gas
+                        assetProxy,                             // call address of asset proxy
+                        0,                                      // don't send any ETH
+                        0,                                      // pointer to start of input
+                        add(164, nestedAssetDataElementLen),    // length of input  
+                        100,                                    // write output over memory that won't be reused
+                        512                                     // reserve 512 bytes for output
+                    )
+
+                    if iszero(success) {
+                        revert(100, returndatasize())
+                    }
+                }
+
+                // Return if no `transferFrom` calls reverted
+                return(0, 0)
+            }
+
+            // Revert if undefined function is called
+            revert(0, 0)
+        }
+    }
+
+    /// @dev Gets the proxy id associated with the proxy address.
+    /// @return Proxy id.
+    function getProxyId()
+        external
+        pure
+        returns (bytes4)
+    {
+        return PROXY_ID;
+    }
+}
\ No newline at end of file
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
index 3e76e38dd..21130a480 100644
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
+++ b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
@@ -18,6 +18,7 @@
 
 // solhint-disable
 pragma solidity 0.4.24;
+pragma experimental ABIEncoderV2;
 
 
 // @dev Interface of the asset proxy's assetData.
@@ -31,8 +32,14 @@ interface IAssetData {
     
     function ERC721Token(
         address tokenContract,
-        uint256 tokenId,
-        bytes receiverData
+        uint256 tokenId
+    )
+        external
+        pure;
+
+    function MultiAsset(
+        uint256[] amounts,
+        bytes[] nestedAssetData
     )
         external
         pure;
-- 
cgit v1.2.3


From 037e63ab49aba623c9878be3d39b8435fa3b987e Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Sun, 11 Nov 2018 20:08:24 -0800
Subject: Factor offsets into calldata locations

---
 .../protocol/AssetProxy/MultiAssetProxy.sol        | 68 +++++++++++++++++-----
 .../protocol/AssetProxy/interfaces/IAssetData.sol  |  9 +--
 2 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 9260ead8f..531ee2264 100644
--- a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -49,7 +49,7 @@ contract MultiAssetProxy is
 
                 // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
                 // where k is the key left padded to 32 bytes and p is the storage slot
-                mstore(0, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
+                mstore(0, caller)
                 mstore(32, authorized_slot)
 
                 // Revert if authorized[msg.sender] == false
@@ -63,7 +63,7 @@ contract MultiAssetProxy is
                 }
 
                 // `transferFrom`.
-                // The function is marked `external`, so no abi decodeding is done for
+                // The function is marked `external`, so no abi decoding is done for
                 // us. Instead, we expect the `calldata` memory to contain the
                 // following:
                 //
@@ -107,20 +107,43 @@ contract MultiAssetProxy is
                 // |          | 132 + a     | b       | nestedAssetData Contents (offsets)  |
                 // |          | 132 + a + b |         | nestedAssetData[0, ..., len]        |
 
-                // Load offset to `amounts`
-                // We must add 4 (function selector) + 32 (assetData len) + 4 (assetProxyId) to the assetData offset
+                // In order to find the offset to `amounts`, we must add:
+                // 4 (function selector)
+                // + assetDataOffset
+                // + 32 (assetData len)
+                // + 4 (assetProxyId)
                 let amountsOffset := calldataload(add(assetDataOffset, 40))
 
-                // Load offsets to `nestedAssetData`
+                // In order to find the offset to `nestedAssetData`, we must add:
+                // 4 (function selector)
+                // + assetDataOffset
+                // + 32 (assetData len)
+                // + 4 (assetProxyId)
+                // + 32 (amounts offset)
                 let nestedAssetDataOffset := calldataload(add(assetDataOffset, 72))
 
+                // In order to find the start of the `amounts` contents, we must add: 
+                // 4 (function selector) 
+                // + assetDataOffset 
+                // + 32 (assetData len)
+                // + 4 (assetProxyId)
+                // + amountsOffset
+                // + 32 (amounts len)
+                let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 72))
+
                 // Load number of elements in `amounts`
-                // We must add 4 (function selector) + 128 (4 params * 32) + 32 (assetData len) + 4 (assetProxyId) + 32 (amounts len) to the amounts offset
-                let amountsContentsStart := add(amountsOffset, 200)
                 let amountsLen := calldataload(sub(amountsContentsStart, 32))
 
+                // In order to find the start of the `nestedAssetData` contents, we must add: 
+                // 4 (function selector) 
+                // + assetDataOffset 
+                // + 32 (assetData len)
+                // + 4 (assetProxyId)
+                // + nestedAssetDataOffset
+                // + 32 (nestedAssetData len)
+                let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 72))
+
                 // Load number of elements in `nestedAssetData`
-                let nestedAssetDataContentsStart := add(nestedAssetDataOffset, 200)
                 let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
 
                 // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
@@ -172,9 +195,20 @@ contract MultiAssetProxy is
                     // Load offset to `nestedAssetData[i]`
                     let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
 
+                    // In order to find the start of the `nestedAssetData[i]` contents, we must add:
+                    // 4 (function selector) 
+                    // + assetDataOffset 
+                    // + 32 (assetData len)
+                    // + 4 (assetProxyId)
+                    // + nestedAssetDataOffset
+                    // + 32 (nestedAssetData len)
+                    // + nestedAssetDataElementOffset
+                    // + 32 (nestedAssetDataElement len)
+                    let nestedAssetDataElementContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, add(nestedAssetDataElementOffset, 104)))
+
                     // Load length of `nestedAssetData[i]`
-                    let nestedAssetDataElementContentsStart := add(nestedAssetDataElementOffset, 264)
-                    let nestedAssetDataElementLen := calldataload(sub(nestedAssetDataElementContentsStart, 32))
+                    let nestedAssetDataElementLenStart := sub(nestedAssetDataElementContentsStart, 32)
+                    let nestedAssetDataElementLen := calldataload(nestedAssetDataElementLenStart)
 
                     // Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId`
                     if lt(nestedAssetDataElementLen, 4) {
@@ -208,7 +242,7 @@ contract MultiAssetProxy is
                     // Copy `nestedAssetData[i]` from calldata to memory
                     calldatacopy(
                         132,                                // memory slot after `amounts[i]`
-                        nestedAssetDataElementOffset,       // location of `nestedAssetData[i]` in calldata
+                        nestedAssetDataElementLenStart,     // location of `nestedAssetData[i]` in calldata
                         add(nestedAssetDataElementLen, 32)  // `nestedAssetData[i].length` plus 32 byte length
                     )
 
@@ -219,12 +253,18 @@ contract MultiAssetProxy is
                         0,                                      // don't send any ETH
                         0,                                      // pointer to start of input
                         add(164, nestedAssetDataElementLen),    // length of input  
-                        100,                                    // write output over memory that won't be reused
-                        512                                     // reserve 512 bytes for output
+                        0,                                      // write output over memory that won't be reused
+                        0                                       // reserve 512 bytes for output
                     )
 
+                    // Revert with reason given by AssetProxy if `transferFrom` call failed
                     if iszero(success) {
-                        revert(100, returndatasize())
+                        returndatacopy(
+                            0,                // copy to memory at 0
+                            0,                // copy from return data at 0
+                            returndatasize()  // copy all return data
+                        )
+                        revert(0, returndatasize())
                     }
                 }
 
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
index 21130a480..e2da68919 100644
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
+++ b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
@@ -27,21 +27,18 @@ pragma experimental ABIEncoderV2;
 interface IAssetData {
 
     function ERC20Token(address tokenContract)
-        external
-        pure;
+        external;
     
     function ERC721Token(
         address tokenContract,
         uint256 tokenId
     )
-        external
-        pure;
+        external;
 
     function MultiAsset(
         uint256[] amounts,
         bytes[] nestedAssetData
     )
-        external
-        pure;
+        external;
     
 }
-- 
cgit v1.2.3


From d146e15ff3741dfd310b4e0b25166bb526b533f0 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Sun, 11 Nov 2018 20:08:58 -0800
Subject: Fix async loops in erc721Wrapper

---
 packages/contracts/test/utils/constants.ts      | 2 +-
 packages/contracts/test/utils/erc721_wrapper.ts | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts
index cd21330e9..d2c3ab512 100644
--- a/packages/contracts/test/utils/constants.ts
+++ b/packages/contracts/test/utils/constants.ts
@@ -35,7 +35,7 @@ export const constants = {
     DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(0),
     NULL_BYTES: '0x',
     NUM_DUMMY_ERC20_TO_DEPLOY: 3,
-    NUM_DUMMY_ERC721_TO_DEPLOY: 1,
+    NUM_DUMMY_ERC721_TO_DEPLOY: 2,
     NUM_ERC721_TOKENS_TO_MINT: 2,
     NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
     UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
diff --git a/packages/contracts/test/utils/erc721_wrapper.ts b/packages/contracts/test/utils/erc721_wrapper.ts
index 3ef4e701d..9bd8fad01 100644
--- a/packages/contracts/test/utils/erc721_wrapper.ts
+++ b/packages/contracts/test/utils/erc721_wrapper.ts
@@ -29,7 +29,7 @@ export class ERC721Wrapper {
         this._contractOwnerAddress = contractOwnerAddress;
     }
     public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
-        for (let i = 0; i < constants.NUM_DUMMY_ERC721_TO_DEPLOY; i++) {
+        for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) {
             this._dummyTokenContracts.push(
                 await DummyERC721TokenContract.deployFrom0xArtifactAsync(
                     artifacts.DummyERC721Token,
@@ -61,7 +61,7 @@ export class ERC721Wrapper {
         this._initialTokenIdsByOwner = {};
         for (const dummyTokenContract of this._dummyTokenContracts) {
             for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
-                for (let i = 0; i < constants.NUM_ERC721_TOKENS_TO_MINT; i++) {
+                for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
                     const tokenId = generatePseudoRandomSalt();
                     await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
                     if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) {
-- 
cgit v1.2.3


From a0bc97b589db46adcc4e2275aa61022c9e224a3f Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Sun, 11 Nov 2018 20:09:13 -0800
Subject: Add initial MultiAssetProxy tests

---
 packages/contracts/package.json                |   6 +-
 packages/contracts/src/artifacts/index.ts      |   2 +
 packages/contracts/test/asset_proxy/proxies.ts | 667 ++++++++++++++++++-------
 packages/contracts/tsconfig.json               |   1 +
 4 files changed, 485 insertions(+), 191 deletions(-)

diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index 25445c4f8..a6380a467 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -19,7 +19,8 @@
         "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
-        "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
+        "run_mocha":
+            "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
         "compile": "sol-compiler --contracts-dir contracts",
         "clean": "shx rm -rf lib generated-artifacts generated-wrappers",
         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
@@ -32,7 +33,8 @@
         "lint-contracts": "solhint contracts/**/**/**/**/*.sol"
     },
     "config": {
-        "abis": "generated-artifacts/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|ERC20Proxy|ERC721Token|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|Whitelist|WETH9|ZRXToken).json"
+        "abis":
+            "generated-artifacts/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|ERC20Proxy|ERC721Token|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiAssetProxy|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|Whitelist|WETH9|ZRXToken).json"
     },
     "repository": {
         "type": "git",
diff --git a/packages/contracts/src/artifacts/index.ts b/packages/contracts/src/artifacts/index.ts
index c30972a91..97c1b6209 100644
--- a/packages/contracts/src/artifacts/index.ts
+++ b/packages/contracts/src/artifacts/index.ts
@@ -19,6 +19,7 @@ import * as InvalidERC721Receiver from '../../generated-artifacts/InvalidERC721R
 import * as IValidator from '../../generated-artifacts/IValidator.json';
 import * as IWallet from '../../generated-artifacts/IWallet.json';
 import * as MixinAuthorizable from '../../generated-artifacts/MixinAuthorizable.json';
+import * as MultiAssetProxy from '../../generated-artifacts/MultiAssetProxy.json';
 import * as MultiSigWallet from '../../generated-artifacts/MultiSigWallet.json';
 import * as MultiSigWalletWithTimeLock from '../../generated-artifacts/MultiSigWalletWithTimeLock.json';
 import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
@@ -57,6 +58,7 @@ export const artifacts = {
     IWallet: IWallet as ContractArtifact,
     InvalidERC721Receiver: InvalidERC721Receiver as ContractArtifact,
     MixinAuthorizable: MixinAuthorizable as ContractArtifact,
+    MultiAssetProxy: MultiAssetProxy as ContractArtifact,
     MultiSigWallet: MultiSigWallet as ContractArtifact,
     MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact,
     OrderValidator: OrderValidator as ContractArtifact,
diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
index b8305993e..94ea408f5 100644
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ b/packages/contracts/test/asset_proxy/proxies.ts
@@ -12,7 +12,9 @@ import { DummyMultipleReturnERC20TokenContract } from '../../generated-wrappers/
 import { DummyNoReturnERC20TokenContract } from '../../generated-wrappers/dummy_no_return_erc20_token';
 import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
 import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
+import { IAssetDataContract } from '../../generated-wrappers/i_asset_data';
 import { IAssetProxyContract } from '../../generated-wrappers/i_asset_proxy';
+import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_proxy';
 import { artifacts } from '../../src/artifacts';
 import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
 import { chaiSetup } from '../utils/chai_setup';
@@ -30,26 +32,35 @@ const assetProxyInterface = new IAssetProxyContract(
     constants.NULL_ADDRESS,
     provider,
 );
+const assetDataInterface = new IAssetDataContract(
+    artifacts.IAssetData.compilerOutput.abi,
+    constants.NULL_ADDRESS,
+    provider,
+);
 
 // tslint:disable:no-unnecessary-type-assertion
-describe('Asset Transfer Proxies', () => {
+describe.only('Asset Transfer Proxies', () => {
     let owner: string;
     let notAuthorized: string;
-    let exchangeAddress: string;
-    let makerAddress: string;
-    let takerAddress: string;
+    let authorized: string;
+    let fromAddress: string;
+    let toAddress: string;
 
-    let zrxToken: DummyERC20TokenContract;
-    let erc721Token: DummyERC721TokenContract;
+    let erc20TokenA: DummyERC20TokenContract;
+    let erc20TokenB: DummyERC20TokenContract;
+    let erc721TokenA: DummyERC721TokenContract;
+    let erc721TokenB: DummyERC721TokenContract;
     let erc721Receiver: DummyERC721ReceiverContract;
     let erc20Proxy: ERC20ProxyContract;
     let erc721Proxy: ERC721ProxyContract;
     let noReturnErc20Token: DummyNoReturnERC20TokenContract;
     let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract;
+    let multiAssetProxy: MultiAssetProxyContract;
 
     let erc20Wrapper: ERC20Wrapper;
     let erc721Wrapper: ERC721Wrapper;
-    let erc721MakerTokenId: BigNumber;
+    let erc721AFromTokenId: BigNumber;
+    let erc721BFromTokenId: BigNumber;
 
     before(async () => {
         await blockchainLifecycle.startAsync();
@@ -59,41 +70,73 @@ describe('Asset Transfer Proxies', () => {
     });
     before(async () => {
         const accounts = await web3Wrapper.getAvailableAddressesAsync();
-        const usedAddresses = ([owner, notAuthorized, exchangeAddress, makerAddress, takerAddress] = _.slice(
-            accounts,
-            0,
-            5,
-        ));
+        const usedAddresses = ([owner, notAuthorized, authorized, fromAddress, toAddress] = _.slice(accounts, 0, 5));
 
         erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
         erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
 
-        const numDummyErc20ToDeploy = 1;
-        [zrxToken] = await erc20Wrapper.deployDummyTokensAsync(numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS);
+        // Deploy AssetProxies
         erc20Proxy = await erc20Wrapper.deployProxyAsync();
-        await erc20Wrapper.setBalancesAndAllowancesAsync();
+        erc721Proxy = await erc721Wrapper.deployProxyAsync();
+        multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
+            artifacts.MultiAssetProxy,
+            provider,
+            txDefaults,
+        );
+
+        // Configure ERC20Proxy
         await web3Wrapper.awaitTransactionSuccessAsync(
-            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeAddress, {
+            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
                 from: owner,
             }),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
 
-        [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
-        erc721Proxy = await erc721Wrapper.deployProxyAsync();
-        await erc721Wrapper.setBalancesAndAllowancesAsync();
-        const erc721Balances = await erc721Wrapper.getBalancesAsync();
-        erc721MakerTokenId = erc721Balances[makerAddress][erc721Token.address][0];
+        // Configure ERC721Proxy
         await web3Wrapper.awaitTransactionSuccessAsync(
-            await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeAddress, {
+            await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
                 from: owner,
             }),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
-        erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
-            artifacts.DummyERC721Receiver,
-            provider,
-            txDefaults,
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+
+        // Configure MultiAssetProxy
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+
+        // Deploy and configure ERC20 tokens
+        const numDummyErc20ToDeploy = 2;
+        [erc20TokenA, erc20TokenB] = await erc20Wrapper.deployDummyTokensAsync(
+            numDummyErc20ToDeploy,
+            constants.DUMMY_TOKEN_DECIMALS,
         );
         noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
             artifacts.DummyNoReturnERC20Token,
@@ -104,30 +147,32 @@ describe('Asset Transfer Proxies', () => {
             constants.DUMMY_TOKEN_DECIMALS,
             constants.DUMMY_TOKEN_TOTAL_SUPPLY,
         );
+        multipleReturnErc20Token = await DummyMultipleReturnERC20TokenContract.deployFrom0xArtifactAsync(
+            artifacts.DummyMultipleReturnERC20Token,
+            provider,
+            txDefaults,
+            constants.DUMMY_TOKEN_NAME,
+            constants.DUMMY_TOKEN_SYMBOL,
+            constants.DUMMY_TOKEN_DECIMALS,
+            constants.DUMMY_TOKEN_TOTAL_SUPPLY,
+        );
+
+        await erc20Wrapper.setBalancesAndAllowancesAsync();
         await web3Wrapper.awaitTransactionSuccessAsync(
-            await noReturnErc20Token.setBalance.sendTransactionAsync(makerAddress, constants.INITIAL_ERC20_BALANCE),
+            await noReturnErc20Token.setBalance.sendTransactionAsync(fromAddress, constants.INITIAL_ERC20_BALANCE),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
         await web3Wrapper.awaitTransactionSuccessAsync(
             await noReturnErc20Token.approve.sendTransactionAsync(
                 erc20Proxy.address,
                 constants.INITIAL_ERC20_ALLOWANCE,
-                { from: makerAddress },
+                { from: fromAddress },
             ),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
-        multipleReturnErc20Token = await DummyMultipleReturnERC20TokenContract.deployFrom0xArtifactAsync(
-            artifacts.DummyMultipleReturnERC20Token,
-            provider,
-            txDefaults,
-            constants.DUMMY_TOKEN_NAME,
-            constants.DUMMY_TOKEN_SYMBOL,
-            constants.DUMMY_TOKEN_DECIMALS,
-            constants.DUMMY_TOKEN_TOTAL_SUPPLY,
-        );
         await web3Wrapper.awaitTransactionSuccessAsync(
             await multipleReturnErc20Token.setBalance.sendTransactionAsync(
-                makerAddress,
+                fromAddress,
                 constants.INITIAL_ERC20_BALANCE,
             ),
             constants.AWAIT_TRANSACTION_MINED_MS,
@@ -136,10 +181,23 @@ describe('Asset Transfer Proxies', () => {
             await multipleReturnErc20Token.approve.sendTransactionAsync(
                 erc20Proxy.address,
                 constants.INITIAL_ERC20_ALLOWANCE,
-                { from: makerAddress },
+                { from: fromAddress },
             ),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
+
+        // Deploy and configure ERC721 tokens and receiver
+        [erc721TokenA, erc721TokenB] = await erc721Wrapper.deployDummyTokensAsync();
+        erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
+            artifacts.DummyERC721Receiver,
+            provider,
+            txDefaults,
+        );
+
+        await erc721Wrapper.setBalancesAndAllowancesAsync();
+        const erc721Balances = await erc721Wrapper.getBalancesAsync();
+        erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0];
+        erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0];
     });
     beforeEach(async () => {
         await blockchainLifecycle.startAsync();
@@ -147,7 +205,8 @@ describe('Asset Transfer Proxies', () => {
     afterEach(async () => {
         await blockchainLifecycle.revertAsync();
     });
-    describe('Transfer Proxy - ERC20', () => {
+
+    describe('ERC20Proxy', () => {
         it('should revert if undefined function is called', async () => {
             const undefinedSelector = '0x01020304';
             await expectTransactionFailedWithoutReasonAsync(
@@ -159,141 +218,146 @@ describe('Asset Transfer Proxies', () => {
                 }),
             );
         });
+        it('should have an id of 0xf47261b0', async () => {
+            const proxyId = await erc20Proxy.getProxyId.callAsync();
+            const expectedProxyId = '0xf47261b0';
+            expect(proxyId).to.equal(expectedProxyId);
+        });
         describe('transferFrom', () => {
             it('should successfully transfer tokens', async () => {
                 // Construct ERC20 asset data
-                const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-                // Perform a transfer from makerAddress to takerAddress
+                const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                // Perform a transfer from fromAddress to toAddress
                 const erc20Balances = await erc20Wrapper.getBalancesAsync();
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
                 // Verify transfer was successful
                 const newBalances = await erc20Wrapper.getBalancesAsync();
-                expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
-                    erc20Balances[makerAddress][zrxToken.address].minus(amount),
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(amount),
                 );
-                expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
-                    erc20Balances[takerAddress][zrxToken.address].add(amount),
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(amount),
                 );
             });
 
             it('should successfully transfer tokens that do not return a value', async () => {
                 // Construct ERC20 asset data
                 const encodedAssetData = assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address);
-                // Perform a transfer from makerAddress to takerAddress
-                const initialMakerBalance = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
-                const initialTakerBalance = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
+                // Perform a transfer from fromAddress to toAddress
+                const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
+                const initialToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
                 // Verify transfer was successful
-                const newMakerBalance = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
-                const newTakerBalance = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
-                expect(newMakerBalance).to.be.bignumber.equal(initialMakerBalance.minus(amount));
-                expect(newTakerBalance).to.be.bignumber.equal(initialTakerBalance.plus(amount));
+                const newFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
+                const newToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
+                expect(newFromBalance).to.be.bignumber.equal(initialFromBalance.minus(amount));
+                expect(newToBalance).to.be.bignumber.equal(initialToBalance.plus(amount));
             });
 
             it('should successfully transfer tokens and ignore extra assetData', async () => {
                 // Construct ERC20 asset data
                 const extraData = '0102030405060708';
-                const encodedAssetData = `${assetDataUtils.encodeERC20AssetData(zrxToken.address)}${extraData}`;
-                // Perform a transfer from makerAddress to takerAddress
+                const encodedAssetData = `${assetDataUtils.encodeERC20AssetData(erc20TokenA.address)}${extraData}`;
+                // Perform a transfer from fromAddress to toAddress
                 const erc20Balances = await erc20Wrapper.getBalancesAsync();
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
                 // Verify transfer was successful
                 const newBalances = await erc20Wrapper.getBalancesAsync();
-                expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
-                    erc20Balances[makerAddress][zrxToken.address].minus(amount),
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(amount),
                 );
-                expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
-                    erc20Balances[takerAddress][zrxToken.address].add(amount),
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(amount),
                 );
             });
 
             it('should do nothing if transferring 0 amount of a token', async () => {
                 // Construct ERC20 asset data
-                const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-                // Perform a transfer from makerAddress to takerAddress
+                const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                // Perform a transfer from fromAddress to toAddress
                 const erc20Balances = await erc20Wrapper.getBalancesAsync();
                 const amount = new BigNumber(0);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
                 // Verify transfer was successful
                 const newBalances = await erc20Wrapper.getBalancesAsync();
-                expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
-                    erc20Balances[makerAddress][zrxToken.address],
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address],
                 );
-                expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
-                    erc20Balances[takerAddress][zrxToken.address],
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address],
                 );
             });
 
-            it('should throw if allowances are too low', async () => {
+            it('should revert if allowances are too low', async () => {
                 // Construct ERC20 asset data
-                const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
+                const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
                 // Create allowance less than transfer amount. Set allowance on proxy.
                 const allowance = new BigNumber(0);
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
-                    await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
-                        from: makerAddress,
+                    await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
+                        from: fromAddress,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
@@ -303,7 +367,7 @@ describe('Asset Transfer Proxies', () => {
                     web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     RevertReason.TransferFailed,
                 );
@@ -311,7 +375,7 @@ describe('Asset Transfer Proxies', () => {
                 expect(newBalances).to.deep.equal(erc20Balances);
             });
 
-            it('should throw if allowances are too low and token does not return a value', async () => {
+            it('should revert if allowances are too low and token does not return a value', async () => {
                 // Construct ERC20 asset data
                 const encodedAssetData = assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address);
                 // Create allowance less than transfer amount. Set allowance on proxy.
@@ -319,42 +383,42 @@ describe('Asset Transfer Proxies', () => {
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await noReturnErc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
-                        from: makerAddress,
+                        from: fromAddress,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
-                const initialMakerBalance = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
-                const initialTakerBalance = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
+                const initialFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
+                const initialToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
                 // Perform a transfer; expect this to fail.
                 await expectTransactionFailedAsync(
                     web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     RevertReason.TransferFailed,
                 );
-                const newMakerBalance = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
-                const newTakerBalance = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
-                expect(newMakerBalance).to.be.bignumber.equal(initialMakerBalance);
-                expect(newTakerBalance).to.be.bignumber.equal(initialTakerBalance);
+                const newFromBalance = await noReturnErc20Token.balanceOf.callAsync(fromAddress);
+                const newToBalance = await noReturnErc20Token.balanceOf.callAsync(toAddress);
+                expect(newFromBalance).to.be.bignumber.equal(initialFromBalance);
+                expect(newToBalance).to.be.bignumber.equal(initialToBalance);
             });
 
-            it('should throw if requesting address is not authorized', async () => {
+            it('should revert if caller is not authorized', async () => {
                 // Construct ERC20 asset data
-                const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-                // Perform a transfer from makerAddress to takerAddress
+                const encodedAssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 const erc20Balances = await erc20Wrapper.getBalancesAsync();
@@ -370,42 +434,36 @@ describe('Asset Transfer Proxies', () => {
                 expect(newBalances).to.deep.equal(erc20Balances);
             });
 
-            it('should throw if token returns more than 32 bytes', async () => {
+            it('should revert if token returns more than 32 bytes', async () => {
                 // Construct ERC20 asset data
                 const encodedAssetData = assetDataUtils.encodeERC20AssetData(multipleReturnErc20Token.address);
                 const amount = new BigNumber(10);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
-                const initialMakerBalance = await multipleReturnErc20Token.balanceOf.callAsync(makerAddress);
-                const initialTakerBalance = await multipleReturnErc20Token.balanceOf.callAsync(takerAddress);
+                const initialFromBalance = await multipleReturnErc20Token.balanceOf.callAsync(fromAddress);
+                const initialToBalance = await multipleReturnErc20Token.balanceOf.callAsync(toAddress);
                 // Perform a transfer; expect this to fail.
                 await expectTransactionFailedAsync(
                     web3Wrapper.sendTransactionAsync({
                         to: erc20Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     RevertReason.TransferFailed,
                 );
-                const newMakerBalance = await multipleReturnErc20Token.balanceOf.callAsync(makerAddress);
-                const newTakerBalance = await multipleReturnErc20Token.balanceOf.callAsync(takerAddress);
-                expect(newMakerBalance).to.be.bignumber.equal(initialMakerBalance);
-                expect(newTakerBalance).to.be.bignumber.equal(initialTakerBalance);
+                const newFromBalance = await multipleReturnErc20Token.balanceOf.callAsync(fromAddress);
+                const newToBalance = await multipleReturnErc20Token.balanceOf.callAsync(toAddress);
+                expect(newFromBalance).to.be.bignumber.equal(initialFromBalance);
+                expect(newToBalance).to.be.bignumber.equal(initialToBalance);
             });
         });
-
-        it('should have an id of 0xf47261b0', async () => {
-            const proxyId = await erc20Proxy.getProxyId.callAsync();
-            const expectedProxyId = '0xf47261b0';
-            expect(proxyId).to.equal(expectedProxyId);
-        });
     });
 
-    describe('Transfer Proxy - ERC721', () => {
+    describe('ERC721Proxy', () => {
         it('should revert if undefined function is called', async () => {
             const undefinedSelector = '0x01020304';
             await expectTransactionFailedWithoutReasonAsync(
@@ -417,76 +475,81 @@ describe('Asset Transfer Proxies', () => {
                 }),
             );
         });
+        it('should have an id of 0x02571792', async () => {
+            const proxyId = await erc721Proxy.getProxyId.callAsync();
+            const expectedProxyId = '0x02571792';
+            expect(proxyId).to.equal(expectedProxyId);
+        });
         describe('transferFrom', () => {
             it('should successfully transfer tokens', async () => {
                 // Construct ERC721 asset data
-                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
+                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Perform a transfer from makerAddress to takerAddress
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(1);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await web3Wrapper.sendTransactionAsync({
                         to: erc721Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
                 // Verify transfer was successful
-                const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
+                const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress);
             });
 
             it('should successfully transfer tokens and ignore extra assetData', async () => {
                 // Construct ERC721 asset data
                 const extraData = '0102030405060708';
                 const encodedAssetData = `${assetDataUtils.encodeERC721AssetData(
-                    erc721Token.address,
-                    erc721MakerTokenId,
+                    erc721TokenA.address,
+                    erc721AFromTokenId,
                 )}${extraData}`;
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Perform a transfer from makerAddress to takerAddress
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(1);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await web3Wrapper.awaitTransactionSuccessAsync(
                     await web3Wrapper.sendTransactionAsync({
                         to: erc721Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
                 // Verify transfer was successful
-                const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
+                const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress);
             });
 
             it('should not call onERC721Received when transferring to a smart contract', async () => {
                 // Construct ERC721 asset data
-                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
+                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Perform a transfer from makerAddress to takerAddress
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(1);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
+                    fromAddress,
                     erc721Receiver.address,
                     amount,
                 );
@@ -495,79 +558,79 @@ describe('Asset Transfer Proxies', () => {
                     await web3Wrapper.sendTransactionAsync({
                         to: erc721Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                         gas: constants.MAX_TRANSFER_FROM_GAS,
                     }),
                 );
                 // Verify that no log was emitted by erc721 receiver
                 expect(tx.logs.length).to.be.equal(1);
                 // Verify transfer was successful
-                const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwnerMakerAsset).to.be.bignumber.equal(erc721Receiver.address);
+                const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwnerFromAsset).to.be.bignumber.equal(erc721Receiver.address);
             });
 
-            it('should throw if transferring 0 amount of a token', async () => {
+            it('should revert if transferring 0 amount of a token', async () => {
                 // Construct ERC721 asset data
-                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
+                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Perform a transfer from makerAddress to takerAddress
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(0);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await expectTransactionFailedAsync(
                     web3Wrapper.sendTransactionAsync({
                         to: erc721Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     RevertReason.InvalidAmount,
                 );
-                const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwner).to.be.equal(ownerMakerAsset);
+                const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwner).to.be.equal(ownerFromAsset);
             });
 
-            it('should throw if transferring > 1 amount of a token', async () => {
+            it('should revert if transferring > 1 amount of a token', async () => {
                 // Construct ERC721 asset data
-                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
+                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Perform a transfer from makerAddress to takerAddress
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(500);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await expectTransactionFailedAsync(
                     web3Wrapper.sendTransactionAsync({
                         to: erc721Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     RevertReason.InvalidAmount,
                 );
-                const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwner).to.be.equal(ownerMakerAsset);
+                const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwner).to.be.equal(ownerFromAsset);
             });
 
-            it('should throw if allowances are too low', async () => {
+            it('should revert if allowances are too low', async () => {
                 // Construct ERC721 asset data
-                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
+                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Remove transfer approval for makerAddress.
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Remove transfer approval for fromAddress.
                 await web3Wrapper.awaitTransactionSuccessAsync(
-                    await erc721Token.approve.sendTransactionAsync(constants.NULL_ADDRESS, erc721MakerTokenId, {
-                        from: makerAddress,
+                    await erc721TokenA.approve.sendTransactionAsync(constants.NULL_ADDRESS, erc721AFromTokenId, {
+                        from: fromAddress,
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
@@ -575,34 +638,34 @@ describe('Asset Transfer Proxies', () => {
                 const amount = new BigNumber(1);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await expectTransactionFailedAsync(
                     web3Wrapper.sendTransactionAsync({
                         to: erc721Proxy.address,
                         data,
-                        from: exchangeAddress,
+                        from: authorized,
                     }),
                     RevertReason.TransferFailed,
                 );
-                const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwner).to.be.equal(ownerMakerAsset);
+                const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwner).to.be.equal(ownerFromAsset);
             });
 
-            it('should throw if requesting address is not authorized', async () => {
+            it('should revert if caller is not authorized', async () => {
                 // Construct ERC721 asset data
-                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
+                const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
                 // Verify pre-condition
-                const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(ownerMakerAsset).to.be.equal(makerAddress);
-                // Perform a transfer from makerAddress to takerAddress
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                // Perform a transfer from fromAddress to toAddress
                 const amount = new BigNumber(1);
                 const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
                     encodedAssetData,
-                    makerAddress,
-                    takerAddress,
+                    fromAddress,
+                    toAddress,
                     amount,
                 );
                 await expectTransactionFailedAsync(
@@ -613,16 +676,242 @@ describe('Asset Transfer Proxies', () => {
                     }),
                     RevertReason.SenderNotAuthorized,
                 );
-                const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
-                expect(newOwner).to.be.equal(ownerMakerAsset);
+                const newOwner = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwner).to.be.equal(ownerFromAsset);
             });
         });
-
-        it('should have an id of 0x02571792', async () => {
-            const proxyId = await erc721Proxy.getProxyId.callAsync();
-            const expectedProxyId = '0x02571792';
+    });
+    describe.only('MultiAssetProxy', () => {
+        it('should revert if undefined function is called', async () => {
+            const undefinedSelector = '0x01020304';
+            await expectTransactionFailedWithoutReasonAsync(
+                web3Wrapper.sendTransactionAsync({
+                    from: owner,
+                    to: multiAssetProxy.address,
+                    value: constants.ZERO_AMOUNT,
+                    data: undefinedSelector,
+                }),
+            );
+        });
+        it('should have an id of 0x94cfcdd7', async () => {
+            const proxyId = await multiAssetProxy.getProxyId.callAsync();
+            const expectedProxyId = '0x94cfcdd7';
             expect(proxyId).to.equal(expectedProxyId);
         });
+        describe('transferFrom', () => {
+            it('should transfer a single ERC20 token', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const amounts = [erc20Amount];
+                const nestedAssetData = [erc20AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                // Verify transfer was successful
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalAmount = inputAmount.times(erc20Amount);
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
+                );
+            });
+            it('should successfully transfer multiple of the same ERC20 token', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount1 = new BigNumber(10);
+                const erc20Amount2 = new BigNumber(20);
+                const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const amounts = [erc20Amount1, erc20Amount2];
+                const nestedAssetData = [erc20AssetData1, erc20AssetData2];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                // Verify transfer was successful
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalAmount = inputAmount.times(erc20Amount1).plus(inputAmount.times(erc20Amount2));
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
+                );
+            });
+            it('should successfully transfer multiple different ERC20 tokens', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount1 = new BigNumber(10);
+                const erc20Amount2 = new BigNumber(20);
+                const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
+                const amounts = [erc20Amount1, erc20Amount2];
+                const nestedAssetData = [erc20AssetData1, erc20AssetData2];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                // Verify transfer was successful
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalErc20AAmount = inputAmount.times(erc20Amount1);
+                const totalErc20BAmount = inputAmount.times(erc20Amount2);
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount),
+                );
+                expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount),
+                );
+            });
+            it('should transfer a single ERC721 token', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc721Amount = new BigNumber(1);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const amounts = [erc721Amount];
+                const nestedAssetData = [erc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwnerFromAsset).to.be.equal(toAddress);
+            });
+            it('should successfully transfer multiple of the same ERC721 token', async () => {
+                const erc721Balances = await erc721Wrapper.getBalancesAsync();
+                const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
+                const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(
+                    erc721TokenA.address,
+                    erc721AFromTokenId2,
+                );
+                const inputAmount = new BigNumber(1);
+                const erc721Amount = new BigNumber(1);
+                const amounts = [erc721Amount, erc721Amount];
+                const nestedAssetData = [erc721AssetData1, erc721AssetData2];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset1).to.be.equal(fromAddress);
+                const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
+                expect(ownerFromAsset2).to.be.equal(fromAddress);
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                        gas: constants.MAX_TRANSFER_FROM_GAS,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
+                expect(newOwnerFromAsset1).to.be.equal(toAddress);
+                expect(newOwnerFromAsset2).to.be.equal(toAddress);
+            });
+            it('should successfully transfer multiple different ERC721 tokens', async () => {
+                const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
+                const inputAmount = new BigNumber(1);
+                const erc721Amount = new BigNumber(1);
+                const amounts = [erc721Amount, erc721Amount];
+                const nestedAssetData = [erc721AssetData1, erc721AssetData2];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset1).to.be.equal(fromAddress);
+                const ownerFromAsset2 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
+                expect(ownerFromAsset2).to.be.equal(fromAddress);
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                        gas: constants.MAX_TRANSFER_FROM_GAS,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                const newOwnerFromAsset2 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
+                expect(newOwnerFromAsset1).to.be.equal(toAddress);
+                expect(newOwnerFromAsset2).to.be.equal(toAddress);
+            });
+            it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {});
+            it('should successfully transfer tokens and ignore extra assetData', async () => {});
+            it('should successfully transfer correct amounts when the `amount` > 1', async () => {});
+            it('should revert if a single transfer fails', async () => {});
+            it('should revert if an AssetProxy is not registered', async () => {});
+            it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {});
+            it('should revert if amounts multiplication results in an overflow', async () => {});
+            it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {});
+            it('should revert with the same reason as the called AssetProxy', async () => {});
+            it('should revert if caller is not authorized', async () => {});
+        });
     });
 });
 // tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json
index 8b29365cc..e0f85079a 100644
--- a/packages/contracts/tsconfig.json
+++ b/packages/contracts/tsconfig.json
@@ -26,6 +26,7 @@
         "./generated-artifacts/IWallet.json",
         "./generated-artifacts/InvalidERC721Receiver.json",
         "./generated-artifacts/MixinAuthorizable.json",
+        "./generated-artifacts/MultiAssetProxy.json",
         "./generated-artifacts/MultiSigWallet.json",
         "./generated-artifacts/MultiSigWalletWithTimeLock.json",
         "./generated-artifacts/OrderValidator.json",
-- 
cgit v1.2.3


From b773d5e592cc0ee57c902c0e2692554f54003234 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 12 Nov 2018 11:22:43 -0800
Subject: feat: Add  and  revert reasons

---
 packages/types/CHANGELOG.json | 9 +++++++++
 packages/types/src/index.ts   | 2 ++
 2 files changed, 11 insertions(+)

diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json
index 0b32b60f0..53b24aff0 100644
--- a/packages/types/CHANGELOG.json
+++ b/packages/types/CHANGELOG.json
@@ -1,4 +1,13 @@
 [
+    {
+        "version": "1.4.0",
+        "changes": [
+            {
+                "note": "Add `LengthMismatch` and `LengthGreaterThan3Required` revert reasons",
+                "pr": 1224
+            }
+        ]
+    },
     {
         "version": "1.3.0",
         "changes": [
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index 1a86f45e6..26d8f8e22 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -195,6 +195,7 @@ export enum RevertReason {
     FailedExecution = 'FAILED_EXECUTION',
     AssetProxyAlreadyExists = 'ASSET_PROXY_ALREADY_EXISTS',
     LengthGreaterThan0Required = 'LENGTH_GREATER_THAN_0_REQUIRED',
+    LengthGreaterThan3Required = 'LENGTH_GREATER_THAN_3_REQUIRED',
     LengthGreaterThan131Required = 'LENGTH_GREATER_THAN_131_REQUIRED',
     Length0Required = 'LENGTH_0_REQUIRED',
     Length65Required = 'LENGTH_65_REQUIRED',
@@ -209,6 +210,7 @@ export enum RevertReason {
     MakerNotWhitelisted = 'MAKER_NOT_WHITELISTED',
     TakerNotWhitelisted = 'TAKER_NOT_WHITELISTED',
     AssetProxyDoesNotExist = 'ASSET_PROXY_DOES_NOT_EXIST',
+    LengthMismatch = 'LENGTH_MISMATCH',
     LibBytesGreaterThanZeroLengthRequired = 'GREATER_THAN_ZERO_LENGTH_REQUIRED',
     LibBytesGreaterOrEqualTo4LengthRequired = 'GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED',
     LibBytesGreaterOrEqualTo20LengthRequired = 'GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED',
-- 
cgit v1.2.3


From 6f92f0a7b5cc9aa9ccd3a1729d6e26da54ebaddf Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 12 Nov 2018 11:23:34 -0800
Subject: Add more tests for MAP

---
 .../protocol/AssetProxy/MultiAssetProxy.sol        |   2 +-
 packages/contracts/test/asset_proxy/proxies.ts     | 355 ++++++++++++++++++++-
 2 files changed, 342 insertions(+), 15 deletions(-)

diff --git a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 531ee2264..fc86ee942 100644
--- a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -286,4 +286,4 @@ contract MultiAssetProxy is
     {
         return PROXY_ID;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
index 94ea408f5..913c91320 100644
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ b/packages/contracts/test/asset_proxy/proxies.ts
@@ -39,7 +39,7 @@ const assetDataInterface = new IAssetDataContract(
 );
 
 // tslint:disable:no-unnecessary-type-assertion
-describe.only('Asset Transfer Proxies', () => {
+describe('Asset Transfer Proxies', () => {
     let owner: string;
     let notAuthorized: string;
     let authorized: string;
@@ -721,7 +721,6 @@ describe.only('Asset Transfer Proxies', () => {
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
-                // Verify transfer was successful
                 const newBalances = await erc20Wrapper.getBalancesAsync();
                 const totalAmount = inputAmount.times(erc20Amount);
                 expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
@@ -755,7 +754,6 @@ describe.only('Asset Transfer Proxies', () => {
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
-                // Verify transfer was successful
                 const newBalances = await erc20Wrapper.getBalancesAsync();
                 const totalAmount = inputAmount.times(erc20Amount1).plus(inputAmount.times(erc20Amount2));
                 expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
@@ -789,7 +787,6 @@ describe.only('Asset Transfer Proxies', () => {
                     }),
                     constants.AWAIT_TRANSACTION_MINED_MS,
                 );
-                // Verify transfer was successful
                 const newBalances = await erc20Wrapper.getBalancesAsync();
                 const totalErc20AAmount = inputAmount.times(erc20Amount1);
                 const totalErc20BAmount = inputAmount.times(erc20Amount2);
@@ -901,16 +898,346 @@ describe.only('Asset Transfer Proxies', () => {
                 expect(newOwnerFromAsset1).to.be.equal(toAddress);
                 expect(newOwnerFromAsset2).to.be.equal(toAddress);
             });
-            it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {});
-            it('should successfully transfer tokens and ignore extra assetData', async () => {});
-            it('should successfully transfer correct amounts when the `amount` > 1', async () => {});
-            it('should revert if a single transfer fails', async () => {});
-            it('should revert if an AssetProxy is not registered', async () => {});
-            it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {});
-            it('should revert if amounts multiplication results in an overflow', async () => {});
-            it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {});
-            it('should revert with the same reason as the called AssetProxy', async () => {});
-            it('should revert if caller is not authorized', async () => {});
+            it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc721Amount = new BigNumber(1);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const amounts = [erc20Amount, erc721Amount];
+                const nestedAssetData = [erc20AssetData, erc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalAmount = inputAmount.times(erc20Amount);
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
+                );
+                const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwnerFromAsset).to.be.equal(toAddress);
+            });
+            it('should successfully transfer tokens and ignore extra assetData', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc721Amount = new BigNumber(1);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const amounts = [erc20Amount, erc721Amount];
+                const nestedAssetData = [erc20AssetData, erc721AssetData];
+                const extraData = '0102030405060708';
+                const assetData = `${assetDataInterface.MultiAsset.getABIEncodedTransactionData(
+                    amounts,
+                    nestedAssetData,
+                )}${extraData}`;
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset).to.be.equal(fromAddress);
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalAmount = inputAmount.times(erc20Amount);
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalAmount),
+                );
+                const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(newOwnerFromAsset).to.be.equal(toAddress);
+            });
+            it('should successfully transfer correct amounts when the `amount` > 1', async () => {
+                const inputAmount = new BigNumber(100);
+                const erc20Amount1 = new BigNumber(10);
+                const erc20Amount2 = new BigNumber(20);
+                const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
+                const amounts = [erc20Amount1, erc20Amount2];
+                const nestedAssetData = [erc20AssetData1, erc20AssetData2];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalErc20AAmount = inputAmount.times(erc20Amount1);
+                const totalErc20BAmount = inputAmount.times(erc20Amount2);
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount),
+                );
+                expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount),
+                );
+            });
+            it('should successfully transfer a large amount of tokens', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount1 = new BigNumber(10);
+                const erc20Amount2 = new BigNumber(20);
+                const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address);
+                const erc721Amount = new BigNumber(1);
+                const erc721Balances = await erc721Wrapper.getBalancesAsync();
+                const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
+                const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1];
+                const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const erc721AssetData2 = assetDataUtils.encodeERC721AssetData(
+                    erc721TokenA.address,
+                    erc721AFromTokenId2,
+                );
+                const erc721AssetData3 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
+                const erc721AssetData4 = assetDataUtils.encodeERC721AssetData(
+                    erc721TokenB.address,
+                    erc721BFromTokenId2,
+                );
+                const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount];
+                const nestedAssetData = [
+                    erc721AssetData1,
+                    erc20AssetData1,
+                    erc721AssetData2,
+                    erc20AssetData2,
+                    erc721AssetData3,
+                    erc721AssetData4,
+                ];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                expect(ownerFromAsset1).to.be.equal(fromAddress);
+                const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
+                expect(ownerFromAsset2).to.be.equal(fromAddress);
+                const ownerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
+                expect(ownerFromAsset3).to.be.equal(fromAddress);
+                const ownerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2);
+                expect(ownerFromAsset4).to.be.equal(fromAddress);
+                const erc20Balances = await erc20Wrapper.getBalancesAsync();
+                await web3Wrapper.awaitTransactionSuccessAsync(
+                    await web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                        gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
+                    }),
+                    constants.AWAIT_TRANSACTION_MINED_MS,
+                );
+                const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
+                const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2);
+                const newOwnerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId);
+                const newOwnerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2);
+                expect(newOwnerFromAsset1).to.be.equal(toAddress);
+                expect(newOwnerFromAsset2).to.be.equal(toAddress);
+                expect(newOwnerFromAsset3).to.be.equal(toAddress);
+                expect(newOwnerFromAsset4).to.be.equal(toAddress);
+                const newBalances = await erc20Wrapper.getBalancesAsync();
+                const totalErc20AAmount = inputAmount.times(erc20Amount1);
+                const totalErc20BAmount = inputAmount.times(erc20Amount2);
+                expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount),
+                );
+                expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal(
+                    erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount),
+                );
+                expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal(
+                    erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount),
+                );
+            });
+            it('should revert if a single transfer fails', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                // 2 is an invalid erc721 amount
+                const erc721Amount = new BigNumber(2);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const amounts = [erc20Amount, erc721Amount];
+                const nestedAssetData = [erc20AssetData, erc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                await expectTransactionFailedAsync(
+                    web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    RevertReason.InvalidAmount,
+                );
+            });
+            it('should revert if an AssetProxy is not registered', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc721Amount = new BigNumber(1);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const invalidProxyId = '0x12345678';
+                const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
+                const amounts = [erc20Amount, erc721Amount];
+                const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                await expectTransactionFailedAsync(
+                    web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    RevertReason.AssetProxyDoesNotExist,
+                );
+            });
+            it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const amounts = [erc20Amount];
+                const nestedAssetData = [erc20AssetData, erc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                await expectTransactionFailedAsync(
+                    web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    RevertReason.LengthMismatch,
+                );
+            });
+            it('should revert if amounts multiplication results in an overflow', async () => {
+                const inputAmount = new BigNumber(2).pow(128);
+                const erc20Amount = new BigNumber(2).pow(128);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const amounts = [erc20Amount];
+                const nestedAssetData = [erc20AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                await expectTransactionFailedAsync(
+                    web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    RevertReason.Uint256Overflow,
+                );
+            });
+            it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc721Amount = new BigNumber(1);
+                const erc721AssetData = '0x123456';
+                const amounts = [erc20Amount, erc721Amount];
+                const nestedAssetData = [erc20AssetData, erc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                await expectTransactionFailedAsync(
+                    web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: authorized,
+                    }),
+                    RevertReason.LengthGreaterThan3Required,
+                );
+            });
+            it('should revert if caller is not authorized', async () => {
+                const inputAmount = new BigNumber(1);
+                const erc20Amount = new BigNumber(10);
+                const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address);
+                const erc721Amount = new BigNumber(1);
+                const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
+                const amounts = [erc20Amount, erc721Amount];
+                const nestedAssetData = [erc20AssetData, erc721AssetData];
+                const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData);
+                const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
+                    assetData,
+                    fromAddress,
+                    toAddress,
+                    inputAmount,
+                );
+                await expectTransactionFailedAsync(
+                    web3Wrapper.sendTransactionAsync({
+                        to: multiAssetProxy.address,
+                        data,
+                        from: notAuthorized,
+                    }),
+                    RevertReason.SenderNotAuthorized,
+                );
+            });
         });
     });
 });
-- 
cgit v1.2.3


From 7b51eddc03762085050eba8dfcf3325360e85403 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 12 Nov 2018 11:28:34 -0800
Subject: Fix linting errors

---
 packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol | 5 ++++-
 packages/contracts/test/utils/erc721_wrapper.ts                      | 2 ++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index fc86ee942..6db42e44f 100644
--- a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -221,7 +221,10 @@ contract MultiAssetProxy is
                     }
 
                     // Load AssetProxy id
-                    let assetProxyId := and(calldataload(nestedAssetDataElementContentsStart), 0xffffffff00000000000000000000000000000000000000000000000000000000)
+                    let assetProxyId := and(
+                        calldataload(nestedAssetDataElementContentsStart),
+                        0xffffffff00000000000000000000000000000000000000000000000000000000
+                    )
 
                     // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
                     // where k is the key left padded to 32 bytes and p is the storage slot
diff --git a/packages/contracts/test/utils/erc721_wrapper.ts b/packages/contracts/test/utils/erc721_wrapper.ts
index 9bd8fad01..e9da553d0 100644
--- a/packages/contracts/test/utils/erc721_wrapper.ts
+++ b/packages/contracts/test/utils/erc721_wrapper.ts
@@ -29,6 +29,7 @@ export class ERC721Wrapper {
         this._contractOwnerAddress = contractOwnerAddress;
     }
     public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
+        // tslint:disable-next-line:no-unused-variable
         for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) {
             this._dummyTokenContracts.push(
                 await DummyERC721TokenContract.deployFrom0xArtifactAsync(
@@ -61,6 +62,7 @@ export class ERC721Wrapper {
         this._initialTokenIdsByOwner = {};
         for (const dummyTokenContract of this._dummyTokenContracts) {
             for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
+                // tslint:disable-next-line:no-unused-variable
                 for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
                     const tokenId = generatePseudoRandomSalt();
                     await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
-- 
cgit v1.2.3


From 743c43f768e4701847cc4299783a09878f2402ee Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 12 Nov 2018 17:17:43 -0800
Subject: Add Exchange tests with MultiAsset orders

---
 packages/contracts/test/asset_proxy/proxies.ts |   2 +-
 packages/contracts/test/exchange/core.ts       | 383 +++++++++++++++++++++++--
 2 files changed, 362 insertions(+), 23 deletions(-)

diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
index 913c91320..face0b92b 100644
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ b/packages/contracts/test/asset_proxy/proxies.ts
@@ -681,7 +681,7 @@ describe('Asset Transfer Proxies', () => {
             });
         });
     });
-    describe.only('MultiAssetProxy', () => {
+    describe('MultiAssetProxy', () => {
         it('should revert if undefined function is called', async () => {
             const undefinedSelector = '0x01020304';
             await expectTransactionFailedWithoutReasonAsync(
diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts
index fc8dc5346..9159b0d8f 100644
--- a/packages/contracts/test/exchange/core.ts
+++ b/packages/contracts/test/exchange/core.ts
@@ -14,6 +14,8 @@ import { DummyNoReturnERC20TokenContract } from '../../generated-wrappers/dummy_
 import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
 import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
 import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated-wrappers/exchange';
+import { IAssetDataContract } from '../../generated-wrappers/i_asset_data';
+import { MultiAssetProxyContract } from '../../generated-wrappers/multi_asset_proxy';
 import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
 import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_static_call_receiver';
 import { artifacts } from '../../src/artifacts';
@@ -31,6 +33,11 @@ import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
 chaiSetup.configure();
 const expect = chai.expect;
 const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
+const assetDataInterface = new IAssetDataContract(
+    artifacts.IAssetData.compilerOutput.abi,
+    constants.NULL_ADDRESS,
+    provider,
+);
 // tslint:disable:no-unnecessary-type-assertion
 describe('Exchange core', () => {
     let makerAddress: string;
@@ -47,6 +54,7 @@ describe('Exchange core', () => {
     let exchange: ExchangeContract;
     let erc20Proxy: ERC20ProxyContract;
     let erc721Proxy: ERC721ProxyContract;
+    let multiAssetProxy: MultiAssetProxyContract;
     let maliciousWallet: TestStaticCallReceiverContract;
     let maliciousValidator: TestStaticCallReceiverContract;
 
@@ -76,59 +84,104 @@ describe('Exchange core', () => {
         erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
         erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
 
+        // Deploy AssetProxies, Exchange, tokens, and malicious contracts
+        erc20Proxy = await erc20Wrapper.deployProxyAsync();
+        erc721Proxy = await erc721Wrapper.deployProxyAsync();
+        multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
+            artifacts.MultiAssetProxy,
+            provider,
+            txDefaults,
+        );
         const numDummyErc20ToDeploy = 3;
         [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
             numDummyErc20ToDeploy,
             constants.DUMMY_TOKEN_DECIMALS,
         );
-        erc20Proxy = await erc20Wrapper.deployProxyAsync();
-        await erc20Wrapper.setBalancesAndAllowancesAsync();
-
         [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
-        erc721Proxy = await erc721Wrapper.deployProxyAsync();
-        await erc721Wrapper.setBalancesAndAllowancesAsync();
-        const erc721Balances = await erc721Wrapper.getBalancesAsync();
-        erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
-        erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
-
         exchange = await ExchangeContract.deployFrom0xArtifactAsync(
             artifacts.Exchange,
             provider,
             txDefaults,
             assetDataUtils.encodeERC20AssetData(zrxToken.address),
         );
-        exchangeWrapper = new ExchangeWrapper(exchange, provider);
-        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
-        await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
+        maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
+            artifacts.TestStaticCallReceiver,
+            provider,
+            txDefaults,
+        );
+        reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
+            artifacts.ReentrantERC20Token,
+            provider,
+            txDefaults,
+            exchange.address,
+        );
 
+        // Configure ERC20Proxy
         await web3Wrapper.awaitTransactionSuccessAsync(
             await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
                 from: owner,
             }),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+
+        // Configure ERC721Proxy
         await web3Wrapper.awaitTransactionSuccessAsync(
             await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
                 from: owner,
             }),
             constants.AWAIT_TRANSACTION_MINED_MS,
         );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
 
-        maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
-            artifacts.TestStaticCallReceiver,
-            provider,
-            txDefaults,
+        // Configure MultiAssetProxy
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
         );
-        reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
-            artifacts.ReentrantERC20Token,
-            provider,
-            txDefaults,
-            exchange.address,
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
+        );
+        await web3Wrapper.awaitTransactionSuccessAsync(
+            await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
+                from: owner,
+            }),
+            constants.AWAIT_TRANSACTION_MINED_MS,
         );
 
+        // Configure Exchange
+        exchangeWrapper = new ExchangeWrapper(exchange, provider);
+        await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
+        await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
+        await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
+
+        // Configure ERC20 tokens
+        await erc20Wrapper.setBalancesAndAllowancesAsync();
+
+        // Configure ERC721 tokens
+        await erc721Wrapper.setBalancesAndAllowancesAsync();
+        const erc721Balances = await erc721Wrapper.getBalancesAsync();
+        erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
+        erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
+
+        // Configure order defaults
         defaultMakerAssetAddress = erc20TokenA.address;
         defaultTakerAssetAddress = erc20TokenB.address;
-
         const defaultOrderParams = {
             ...constants.STATIC_ORDER_PARAMS,
             exchangeAddress: exchange.address,
@@ -707,6 +760,292 @@ describe('Exchange core', () => {
         });
     });
 
+    describe('Testing exchange of multiple assets', () => {
+        it('should allow multiple assets to be exchanged for a single asset', async () => {
+            const makerAmounts = [new BigNumber(10), new BigNumber(20)];
+            const makerNestedAssetData = [
+                assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
+                assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
+            ];
+            const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
+                makerAmounts,
+                makerNestedAssetData,
+            );
+            const makerAssetAmount = new BigNumber(1);
+            const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
+            const takerAssetAmount = new BigNumber(10);
+            signedOrder = await orderFactory.newSignedOrderAsync({
+                makerAssetData,
+                takerAssetData,
+                makerAssetAmount,
+                takerAssetAmount,
+                makerFee: constants.ZERO_AMOUNT,
+                takerFee: constants.ZERO_AMOUNT,
+            });
+
+            const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+
+            await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
+
+            const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+
+            expect(finalMakerBalanceA).to.be.bignumber.equal(
+                initialMakerBalanceA.minus(makerAmounts[0].times(makerAssetAmount)),
+            );
+            expect(finalMakerBalanceB).to.be.bignumber.equal(
+                initialMakerBalanceB.minus(makerAmounts[1].times(makerAssetAmount)),
+            );
+            expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.plus(takerAssetAmount));
+            expect(finalTakerBalanceA).to.be.bignumber.equal(
+                initialTakerBalanceA.plus(makerAmounts[0].times(makerAssetAmount)),
+            );
+            expect(finalTakerBalanceB).to.be.bignumber.equal(
+                initialTakerBalanceB.plus(makerAmounts[1].times(makerAssetAmount)),
+            );
+            expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(takerAssetAmount));
+        });
+        it('should allow multiple assets to be exchanged for multiple assets', async () => {
+            const makerAmounts = [new BigNumber(10), new BigNumber(20)];
+            const makerNestedAssetData = [
+                assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
+                assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
+            ];
+            const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
+                makerAmounts,
+                makerNestedAssetData,
+            );
+            const makerAssetAmount = new BigNumber(1);
+            const takerAmounts = [new BigNumber(10), new BigNumber(1)];
+            const takerAssetId = erc721TakerAssetIds[0];
+            const takerNestedAssetData = [
+                assetDataUtils.encodeERC20AssetData(zrxToken.address),
+                assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
+            ];
+            const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
+                takerAmounts,
+                takerNestedAssetData,
+            );
+            const takerAssetAmount = new BigNumber(1);
+            signedOrder = await orderFactory.newSignedOrderAsync({
+                makerAssetData,
+                takerAssetData,
+                makerAssetAmount,
+                takerAssetAmount,
+                makerFee: constants.ZERO_AMOUNT,
+                takerFee: constants.ZERO_AMOUNT,
+            });
+
+            const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+            const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
+            expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
+
+            await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
+
+            const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+            const finalOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
+
+            expect(finalMakerBalanceA).to.be.bignumber.equal(
+                initialMakerBalanceA.minus(makerAmounts[0].times(makerAssetAmount)),
+            );
+            expect(finalMakerBalanceB).to.be.bignumber.equal(
+                initialMakerBalanceB.minus(makerAmounts[1].times(makerAssetAmount)),
+            );
+            expect(finalMakerZrxBalance).to.be.bignumber.equal(
+                initialMakerZrxBalance.plus(takerAmounts[0].times(takerAssetAmount)),
+            );
+            expect(finalTakerBalanceA).to.be.bignumber.equal(
+                initialTakerBalanceA.plus(makerAmounts[0].times(makerAssetAmount)),
+            );
+            expect(finalTakerBalanceB).to.be.bignumber.equal(
+                initialTakerBalanceB.plus(makerAmounts[1].times(makerAssetAmount)),
+            );
+            expect(finalTakerZrxBalance).to.be.bignumber.equal(
+                initialTakerZrxBalance.minus(takerAmounts[0].times(takerAssetAmount)),
+            );
+            expect(finalOwnerTakerAsset).to.be.equal(makerAddress);
+        });
+        it('should allow an order selling multiple assets to be partially filled', async () => {
+            const makerAmounts = [new BigNumber(10), new BigNumber(20)];
+            const makerNestedAssetData = [
+                assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
+                assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
+            ];
+            const makerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
+                makerAmounts,
+                makerNestedAssetData,
+            );
+            const makerAssetAmount = new BigNumber(30);
+            const takerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
+            const takerAssetAmount = new BigNumber(10);
+            signedOrder = await orderFactory.newSignedOrderAsync({
+                makerAssetData,
+                takerAssetData,
+                makerAssetAmount,
+                takerAssetAmount,
+                makerFee: constants.ZERO_AMOUNT,
+                takerFee: constants.ZERO_AMOUNT,
+            });
+
+            const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+
+            const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2);
+            await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
+                takerAssetFillAmount,
+            });
+
+            const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+
+            expect(finalMakerBalanceA).to.be.bignumber.equal(
+                initialMakerBalanceA.minus(
+                    makerAmounts[0].times(
+                        makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalMakerBalanceB).to.be.bignumber.equal(
+                initialMakerBalanceB.minus(
+                    makerAmounts[1].times(
+                        makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalMakerZrxBalance).to.be.bignumber.equal(
+                initialMakerZrxBalance.plus(
+                    takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                ),
+            );
+            expect(finalTakerBalanceA).to.be.bignumber.equal(
+                initialTakerBalanceA.plus(
+                    makerAmounts[0].times(
+                        makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalTakerBalanceB).to.be.bignumber.equal(
+                initialTakerBalanceB.plus(
+                    makerAmounts[1].times(
+                        makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalTakerZrxBalance).to.be.bignumber.equal(
+                initialTakerZrxBalance.minus(
+                    takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                ),
+            );
+        });
+        it('should allow an order buying multiple assets to be partially filled', async () => {
+            const takerAmounts = [new BigNumber(10), new BigNumber(20)];
+            const takerNestedAssetData = [
+                assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
+                assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
+            ];
+            const takerAssetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(
+                takerAmounts,
+                takerNestedAssetData,
+            );
+            const takerAssetAmount = new BigNumber(30);
+            const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
+            const makerAssetAmount = new BigNumber(10);
+            signedOrder = await orderFactory.newSignedOrderAsync({
+                makerAssetData,
+                takerAssetData,
+                makerAssetAmount,
+                takerAssetAmount,
+                makerFee: constants.ZERO_AMOUNT,
+                takerFee: constants.ZERO_AMOUNT,
+            });
+
+            const initialMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const initialTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+
+            const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2);
+            await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
+                takerAssetFillAmount,
+            });
+
+            const finalMakerBalanceA = await erc20TokenA.balanceOf.callAsync(makerAddress);
+            const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
+            const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
+            const finalTakerBalanceA = await erc20TokenA.balanceOf.callAsync(takerAddress);
+            const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
+            const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
+
+            expect(finalMakerBalanceA).to.be.bignumber.equal(
+                initialMakerBalanceA.plus(
+                    takerAmounts[0].times(
+                        takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalMakerBalanceB).to.be.bignumber.equal(
+                initialMakerBalanceB.plus(
+                    takerAmounts[1].times(
+                        takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalMakerZrxBalance).to.be.bignumber.equal(
+                initialMakerZrxBalance.minus(
+                    makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                ),
+            );
+            expect(finalTakerBalanceA).to.be.bignumber.equal(
+                initialTakerBalanceA.minus(
+                    takerAmounts[0].times(
+                        takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalTakerBalanceB).to.be.bignumber.equal(
+                initialTakerBalanceB.minus(
+                    takerAmounts[1].times(
+                        takerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                    ),
+                ),
+            );
+            expect(finalTakerZrxBalance).to.be.bignumber.equal(
+                initialTakerZrxBalance.plus(
+                    makerAssetAmount.times(takerAssetFillAmount).dividedToIntegerBy(takerAssetAmount),
+                ),
+            );
+        });
+    });
+
     describe('getOrderInfo', () => {
         beforeEach(async () => {
             signedOrder = await orderFactory.newSignedOrderAsync();
-- 
cgit v1.2.3


From 0b9e9eb0e4fb58ffbda84f0e77c3b0c83902d669 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 26 Nov 2018 17:52:16 -0800
Subject: Don't load assetProxy if currentProxyid is equal to the last seen
 proxyid

---
 .../protocol/AssetProxy/MultiAssetProxy.sol        | 26 ++++++++++++++--------
 packages/contracts/test/asset_proxy/proxies.ts     |  1 +
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
index 6db42e44f..42231e73b 100644
--- a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
+++ b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol
@@ -18,13 +18,11 @@
 
 pragma solidity 0.4.24;
 
-import "../../utils/SafeMath/SafeMath.sol";
 import "../Exchange/MixinAssetProxyDispatcher.sol";
 import "./MixinAuthorizable.sol";
 
 
 contract MultiAssetProxy is
-    SafeMath,
     MixinAssetProxyDispatcher,
     MixinAuthorizable
 {
@@ -172,6 +170,10 @@ contract MultiAssetProxy is
                 // Calculate number of bytes in `amounts` contents
                 let amountsByteLen := mul(amountsLen, 32)
 
+                // Initialize `assetProxyId` and `assetProxy` to 0
+                let assetProxyId := 0
+                let assetProxy := 0
+
                 // Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element
                 for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} {
 
@@ -221,16 +223,22 @@ contract MultiAssetProxy is
                     }
 
                     // Load AssetProxy id
-                    let assetProxyId := and(
+                    let currentAssetProxyId := and(
                         calldataload(nestedAssetDataElementContentsStart),
                         0xffffffff00000000000000000000000000000000000000000000000000000000
                     )
 
-                    // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
-                    // where k is the key left padded to 32 bytes and p is the storage slot
-                    mstore(132, assetProxyId)
-                    mstore(164, assetProxies_slot)
-                    let assetProxy := sload(keccak256(132, 64))
+                    // Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId`
+                    // We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0
+                    if iszero(eq(currentAssetProxyId, assetProxyId)) {
+                        // Update `assetProxyId`
+                        assetProxyId := currentAssetProxyId
+                        // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
+                        // where k is the key left padded to 32 bytes and p is the storage slot
+                        mstore(132, assetProxyId)
+                        mstore(164, assetProxies_slot)
+                        assetProxy := sload(keccak256(132, 64))
+                    }
                     
                     // Revert if AssetProxy with given id does not exist
                     if iszero(assetProxy) {
@@ -257,7 +265,7 @@ contract MultiAssetProxy is
                         0,                                      // pointer to start of input
                         add(164, nestedAssetDataElementLen),    // length of input  
                         0,                                      // write output over memory that won't be reused
-                        0                                       // reserve 512 bytes for output
+                        0                                       // don't copy output to memory
                     )
 
                     // Revert with reason given by AssetProxy if `transferFrom` call failed
diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
index face0b92b..8fa1e602a 100644
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ b/packages/contracts/test/asset_proxy/proxies.ts
@@ -695,6 +695,7 @@ describe('Asset Transfer Proxies', () => {
         });
         it('should have an id of 0x94cfcdd7', async () => {
             const proxyId = await multiAssetProxy.getProxyId.callAsync();
+            // first 4 bytes of `keccak256('MultiAsset(uint256[],bytes[])')`
             const expectedProxyId = '0x94cfcdd7';
             expect(proxyId).to.equal(expectedProxyId);
         });
-- 
cgit v1.2.3


From 708f4e9bb887431dec278546f2c01c124f8b61c2 Mon Sep 17 00:00:00 2001
From: Amir Bandeali <abandeali1@gmail.com>
Date: Mon, 26 Nov 2018 17:52:53 -0800
Subject: Update CHANGELOG

---
 packages/contracts/CHANGELOG.json | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/packages/contracts/CHANGELOG.json b/packages/contracts/CHANGELOG.json
index 00f94c83b..7dfa06990 100644
--- a/packages/contracts/CHANGELOG.json
+++ b/packages/contracts/CHANGELOG.json
@@ -1,4 +1,14 @@
 [
+    {
+        "name": "MultiAssetProxy",
+        "version": "1.0.0",
+        "changes": [
+            {
+                "note": "Add MultiAssetProxy implementation",
+                "pr": 1224
+            }
+        ]
+    },
     {
         "name": "OrderValidator",
         "version": "1.0.1",
-- 
cgit v1.2.3


From ca894935f269a385f28e5d3a51720282ab403697 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 10:07:11 -0800
Subject: Take out asset name and data as we can use the selected event
 properties

---
 packages/instant/src/util/analytics.ts         | 10 +---------
 packages/instant/src/util/buy_quote_updater.ts |  8 +-------
 2 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index dd6021453..b85c6cee2 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -185,17 +185,9 @@ export const analytics = {
             ...buyQuoteEventProperties(buyQuote),
             fetchedVia,
         }),
-    trackQuoteError: (
-        errorMessage: string,
-        assetName: string,
-        assetData: string,
-        assetAmount: BigNumber,
-        fetchedVia: QuoteFetchedVia,
-    ) => {
+    trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchedVia) => {
         trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({
             errorMessage,
-            assetName,
-            assetData,
             assetAmount: assetAmount.toString(),
             fetchedVia,
         });
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 3c982ed1f..d6c4bd71b 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -37,13 +37,7 @@ export const buyQuoteUpdater = {
         } catch (error) {
             if (options.dispatchErrors) {
                 dispatch(actions.setQuoteRequestStateFailure());
-                analytics.trackQuoteError(
-                    error.message ? error.message : 'other',
-                    asset.metaData.name,
-                    asset.assetData,
-                    assetUnitAmount,
-                    options.fetchedVia,
-                );
+                analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, options.fetchedVia);
                 let errorMessage;
                 if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
                     const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
-- 
cgit v1.2.3


From 1b23c430fcb6e4e816b60f85343b5fe009ab4754 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 10:25:04 -0800
Subject: fix(instant): Half opacity instead of darkening on hover for
 clickable text

---
 packages/instant/src/components/ui/text.tsx | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx
index 8e573d7b9..e149e2d8e 100644
--- a/packages/instant/src/components/ui/text.tsx
+++ b/packages/instant/src/components/ui/text.tsx
@@ -31,7 +31,7 @@ export const Text: React.StatelessComponent<TextProps> = ({ href, onClick, ...re
     return <StyledText {...rest} onClick={computedOnClick} />;
 };
 
-const darkenOnHoverAmount = 0.3;
+const opacityOnHoverAmount = 0.5;
 export const StyledText =
     styled.div <
     TextProps >
@@ -56,8 +56,7 @@ export const StyledText =
         ${props => (props.textAlign ? `text-align: ${props.textAlign}` : '')};
         ${props => (props.width ? `width: ${props.width}` : '')};
         &:hover {
-            ${props =>
-                props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''};
+            ${props => (props.onClick ? `opacity: ${opacityOnHoverAmount};` : '')};
         }
     }
 `;
-- 
cgit v1.2.3


From 06b2f12b10c6c2030b326b3e817d497415862299 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 10:38:24 -0800
Subject: fix(instant): Fix uncontrolled input warning for token selector

---
 packages/instant/src/components/erc20_token_selector.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
index 0a3d4427a..f7d5a4fe4 100644
--- a/packages/instant/src/components/erc20_token_selector.tsx
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -19,12 +19,12 @@ export interface ERC20TokenSelectorProps {
 }
 
 export interface ERC20TokenSelectorState {
-    searchQuery?: string;
+    searchQuery: string;
 }
 
 export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> {
     public state: ERC20TokenSelectorState = {
-        searchQuery: undefined,
+        searchQuery: '',
     };
     public render(): React.ReactNode {
         const { tokens, onTokenSelect } = this.props;
@@ -62,10 +62,10 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
     };
     private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => {
         const { searchQuery } = this.state;
-        if (_.isUndefined(searchQuery)) {
+        const searchQueryLowerCase = searchQuery.toLowerCase().trim();
+        if (searchQueryLowerCase === '') {
             return true;
         }
-        const searchQueryLowerCase = searchQuery.toLowerCase();
         const tokenName = token.metaData.name.toLowerCase();
         const tokenSymbol = token.metaData.symbol.toLowerCase();
         return _.startsWith(tokenSymbol, searchQueryLowerCase) || _.startsWith(tokenName, searchQueryLowerCase);
-- 
cgit v1.2.3


From 3c000e70e3fe507b199871879dde54bcefe01e1e Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 10:48:38 -0800
Subject: Linting

---
 packages/instant/src/components/ui/text.tsx | 1 -
 1 file changed, 1 deletion(-)

diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx
index e149e2d8e..282477758 100644
--- a/packages/instant/src/components/ui/text.tsx
+++ b/packages/instant/src/components/ui/text.tsx
@@ -1,4 +1,3 @@
-import { darken } from 'polished';
 import * as React from 'react';
 
 import { ColorOption, styled } from '../../style/theme';
-- 
cgit v1.2.3


From 85d1dba1ef5ba4d34de46cb7eb54bfdc7acae380 Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
Date: Wed, 28 Nov 2018 13:35:38 -0800
Subject: fix: notify of the used font size for re-renders of scaling input

---
 packages/instant/src/components/scaling_input.tsx | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 129162a74..791692257 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -98,6 +98,12 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
             inputWidthPx: this._getInputWidthInPx(),
         };
     }
+    public componentDidMount(): void {
+        // Trigger an initial notification of the calculated fontSize.
+        const currentPhase = ScalingInput.getPhaseFromProps(this.props);
+        const currentFontSize = ScalingInput.calculateFontSizeFromProps(this.props, currentPhase);
+        this.props.onFontSizeChange(currentFontSize);
+    }
     public componentDidUpdate(
         prevProps: ScalingInputProps,
         prevState: ScalingInputState,
-- 
cgit v1.2.3


From 105dcd73e473bf347a3db0143f7730d46fa44d84 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Tue, 27 Nov 2018 16:19:50 -0800
Subject: fix(instant): Progress bar background color should be 10% primary
 color

---
 packages/instant/src/components/timed_progress_bar.tsx | 17 +++++++++++++----
 packages/instant/src/components/ui/container.tsx       | 13 ++++++++++++-
 packages/instant/src/style/theme.ts                    | 12 ++++++++++--
 3 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx
index 8465b9cd0..fb3927088 100644
--- a/packages/instant/src/components/timed_progress_bar.tsx
+++ b/packages/instant/src/components/timed_progress_bar.tsx
@@ -1,8 +1,9 @@
 import * as _ from 'lodash';
+import { transparentize } from 'polished';
 import * as React from 'react';
 
 import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_WIDTH } from '../constants';
-import { ColorOption, css, keyframes, styled } from '../style/theme';
+import { ColorOption, css, keyframes, styled, ThemeConsumer } from '../style/theme';
 
 import { Container } from './ui/container';
 
@@ -93,8 +94,16 @@ export interface ProgressBarProps extends ProgressProps {}
 
 export const ProgressBar: React.ComponentType<ProgressBarProps & React.ClassAttributes<{}>> = React.forwardRef(
     (props, ref) => (
-        <Container width="100%" backgroundColor={ColorOption.lightGrey} borderRadius="6px">
-            <Progress {...props} ref={ref as any} />
-        </Container>
+        <ThemeConsumer>
+            {theme => (
+                <Container
+                    width="100%"
+                    borderRadius="6px"
+                    rawBackgroundColor={transparentize(0.5, theme[ColorOption.primaryColor])}
+                >
+                    <Progress {...props} ref={ref as any} />
+                </Container>
+            )}
+        </ThemeConsumer>
     ),
 );
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
index 4dafe1386..a015ab5bc 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -27,6 +27,7 @@ export interface ContainerProps {
     borderBottom?: string;
     className?: string;
     backgroundColor?: ColorOption;
+    rawBackgroundColor?: string;
     hasBoxShadow?: boolean;
     zIndex?: number;
     whiteSpace?: string;
@@ -38,6 +39,16 @@ export interface ContainerProps {
     flexGrow?: string | number;
 }
 
+const getBackgroundColor = (theme: any, backgroundColor?: ColorOption, rawBackgroundColor?: string): string => {
+    if (backgroundColor) {
+        return theme[backgroundColor] as string;
+    }
+    if (rawBackgroundColor) {
+        return rawBackgroundColor;
+    }
+    return 'none';
+};
+
 export const Container =
     styled.div <
     ContainerProps >
@@ -70,7 +81,7 @@ export const Container =
         ${props => props.width && stylesForMedia<string>('width', props.width)}
         ${props => props.height && stylesForMedia<string>('height', props.height)}
         ${props => props.borderRadius && stylesForMedia<string>('border-radius', props.borderRadius)}
-        background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+        background-color: ${props => getBackgroundColor(props.theme, props.backgroundColor, props.rawBackgroundColor)};
         border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
         &:hover {
             ${props =>
diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts
index a0751286b..71e4b7052 100644
--- a/packages/instant/src/style/theme.ts
+++ b/packages/instant/src/style/theme.ts
@@ -1,6 +1,14 @@
 import * as styledComponents from 'styled-components';
 
-const { default: styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider } = styledComponents;
+const {
+    default: styled,
+    css,
+    keyframes,
+    withTheme,
+    createGlobalStyle,
+    ThemeConsumer,
+    ThemeProvider,
+} = styledComponents;
 
 export type Theme = { [key in ColorOption]: string };
 
@@ -45,4 +53,4 @@ export const generateOverlayBlack = (opacity = 0.6) => {
     return `rgba(0, 0, 0, ${opacity})`;
 };
 
-export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider };
+export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeConsumer, ThemeProvider };
-- 
cgit v1.2.3


From f4cc14f43862c639d2cf9f6e5359e4822f1bcacf Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 14:11:06 -0800
Subject: QuoteFetchedVia -> QuoteFetchOrigin

---
 packages/instant/src/components/zero_ex_instant_provider.tsx        | 4 ++--
 .../instant/src/containers/selected_erc20_asset_amount_input.ts     | 4 ++--
 packages/instant/src/redux/async_data.ts                            | 4 ++--
 packages/instant/src/types.ts                                       | 2 +-
 packages/instant/src/util/analytics.ts                              | 6 +++---
 packages/instant/src/util/buy_quote_updater.ts                      | 4 ++--
 packages/instant/src/util/heartbeater_factory.ts                    | 4 ++--
 7 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 9f2c95e36..7841f5bf7 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -11,7 +11,7 @@ import { asyncData } from '../redux/async_data';
 import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer';
 import { store, Store } from '../redux/store';
 import { fonts } from '../style/fonts';
-import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchedVia } from '../types';
+import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource, QuoteFetchOrigin } from '../types';
 import { analytics, disableAnalytics } from '../util/analytics';
 import { assetUtils } from '../util/asset';
 import { errorFlasher } from '../util/error_flasher';
@@ -117,7 +117,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
         // tslint:disable-next-line:no-floating-promises
         asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, {
             updateSilently: false,
-            fetchedVia: QuoteFetchedVia.Manual,
+            fetchedVia: QuoteFetchOrigin.Manual,
         });
         // warm up the gas price estimator cache just in case we can't
         // grab the gas price estimate when submitting the transaction
diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
index 1e9b22617..a2d523b82 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -10,7 +10,7 @@ import { ERC20AssetAmountInput, ERC20AssetAmountInputProps } from '../components
 import { Action, actions } from '../redux/actions';
 import { State } from '../redux/reducer';
 import { ColorOption } from '../style/theme';
-import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState, QuoteFetchedVia } from '../types';
+import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState, QuoteFetchOrigin } from '../types';
 import { buyQuoteUpdater } from '../util/buy_quote_updater';
 
 export interface SelectedERC20AssetAmountInputProps {
@@ -92,7 +92,7 @@ const mapDispatchToProps = (
                 setPending: true,
                 dispatchErrors: true,
                 affiliateInfo,
-                fetchedVia: QuoteFetchedVia.Manual,
+                fetchedVia: QuoteFetchOrigin.Manual,
             });
         }
     },
diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts
index 2efc3698f..6a1d2ed00 100644
--- a/packages/instant/src/redux/async_data.ts
+++ b/packages/instant/src/redux/async_data.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 import { Dispatch } from 'redux';
 
 import { BIG_NUMBER_ZERO } from '../constants';
-import { AccountState, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchedVia } from '../types';
+import { AccountState, ERC20Asset, OrderProcessState, ProviderState, QuoteFetchOrigin } from '../types';
 import { analytics } from '../util/analytics';
 import { assetUtils } from '../util/asset';
 import { buyQuoteUpdater } from '../util/buy_quote_updater';
@@ -84,7 +84,7 @@ export const asyncData = {
     fetchCurrentBuyQuoteAndDispatchToStore: async (
         state: State,
         dispatch: Dispatch,
-        options: { updateSilently: boolean; fetchedVia: QuoteFetchedVia },
+        options: { updateSilently: boolean; fetchedVia: QuoteFetchOrigin },
     ) => {
         const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
         const assetBuyer = providerState.assetBuyer;
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index a8139c185..ea2bcbc2f 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -21,7 +21,7 @@ export enum OrderProcessState {
     Failure = 'FAILURE',
 }
 
-export enum QuoteFetchedVia {
+export enum QuoteFetchOrigin {
     Manual = 'Manual',
     Heartbeat = 'Heartbeat',
 }
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index b85c6cee2..c0ed8c638 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer';
 import { BigNumber } from '@0x/utils';
 import * as _ from 'lodash';
 
-import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchedVia } from '../types';
+import { AffiliateInfo, Asset, Network, OrderSource, ProviderState, QuoteFetchOrigin } from '../types';
 
 import { EventProperties, heapUtil } from './heap';
 
@@ -180,12 +180,12 @@ export const analytics = {
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload),
     trackTokenSelectorSearched: (searchText: string) =>
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }),
-    trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchedVia) =>
+    trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchOrigin) =>
         trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({
             ...buyQuoteEventProperties(buyQuote),
             fetchedVia,
         }),
-    trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchedVia) => {
+    trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchOrigin) => {
         trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({
             errorMessage,
             assetAmount: assetAmount.toString(),
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index d6c4bd71b..14af57660 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -6,7 +6,7 @@ import { Dispatch } from 'redux';
 import { oc } from 'ts-optchain';
 
 import { Action, actions } from '../redux/actions';
-import { AffiliateInfo, ERC20Asset, QuoteFetchedVia } from '../types';
+import { AffiliateInfo, ERC20Asset, QuoteFetchOrigin } from '../types';
 import { analytics } from '../util/analytics';
 import { assetUtils } from '../util/asset';
 import { errorFlasher } from '../util/error_flasher';
@@ -20,7 +20,7 @@ export const buyQuoteUpdater = {
         options: {
             setPending: boolean;
             dispatchErrors: boolean;
-            fetchedVia: QuoteFetchedVia;
+            fetchedVia: QuoteFetchOrigin;
             affiliateInfo?: AffiliateInfo;
         },
     ): Promise<void> => {
diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts
index bf9e4291f..84aeb4dbc 100644
--- a/packages/instant/src/util/heartbeater_factory.ts
+++ b/packages/instant/src/util/heartbeater_factory.ts
@@ -1,6 +1,6 @@
 import { asyncData } from '../redux/async_data';
 import { Store } from '../redux/store';
-import { QuoteFetchedVia } from '../types';
+import { QuoteFetchOrigin } from '../types';
 
 import { Heartbeater } from './heartbeater';
 
@@ -20,7 +20,7 @@ export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): H
     return new Heartbeater(async () => {
         await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, {
             updateSilently: true,
-            fetchedVia: QuoteFetchedVia.Heartbeat,
+            fetchedVia: QuoteFetchOrigin.Heartbeat,
         });
     }, shouldPerformImmediatelyOnStart);
 };
-- 
cgit v1.2.3


From ec01893e9c987fcbd3fd7bcb4ec34498a6f516cc Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 14:11:53 -0800
Subject: fetchedVia -> fetchOrigin

---
 packages/instant/src/components/zero_ex_instant_provider.tsx   |  2 +-
 .../src/containers/selected_erc20_asset_amount_input.ts        |  2 +-
 packages/instant/src/redux/async_data.ts                       |  4 ++--
 packages/instant/src/util/analytics.ts                         |  8 ++++----
 packages/instant/src/util/buy_quote_updater.ts                 | 10 +++++++---
 packages/instant/src/util/heartbeater_factory.ts               |  2 +-
 6 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 7841f5bf7..f7880fc12 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -117,7 +117,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
         // tslint:disable-next-line:no-floating-promises
         asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, {
             updateSilently: false,
-            fetchedVia: QuoteFetchOrigin.Manual,
+            fetchOrigin: QuoteFetchOrigin.Manual,
         });
         // warm up the gas price estimator cache just in case we can't
         // grab the gas price estimate when submitting the transaction
diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
index a2d523b82..40e35b575 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -92,7 +92,7 @@ const mapDispatchToProps = (
                 setPending: true,
                 dispatchErrors: true,
                 affiliateInfo,
-                fetchedVia: QuoteFetchOrigin.Manual,
+                fetchOrigin: QuoteFetchOrigin.Manual,
             });
         }
     },
diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts
index 6a1d2ed00..dc73fd9af 100644
--- a/packages/instant/src/redux/async_data.ts
+++ b/packages/instant/src/redux/async_data.ts
@@ -84,7 +84,7 @@ export const asyncData = {
     fetchCurrentBuyQuoteAndDispatchToStore: async (
         state: State,
         dispatch: Dispatch,
-        options: { updateSilently: boolean; fetchedVia: QuoteFetchOrigin },
+        options: { updateSilently: boolean; fetchOrigin: QuoteFetchOrigin },
     ) => {
         const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
         const assetBuyer = providerState.assetBuyer;
@@ -102,7 +102,7 @@ export const asyncData = {
                 {
                     setPending: !options.updateSilently,
                     dispatchErrors: !options.updateSilently,
-                    fetchedVia: options.fetchedVia,
+                    fetchOrigin: options.fetchOrigin,
                     affiliateInfo,
                 },
             );
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index c0ed8c638..99e8736d3 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -180,16 +180,16 @@ export const analytics = {
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload),
     trackTokenSelectorSearched: (searchText: string) =>
         trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }),
-    trackQuoteFetched: (buyQuote: BuyQuote, fetchedVia: QuoteFetchOrigin) =>
+    trackQuoteFetched: (buyQuote: BuyQuote, fetchOrigin: QuoteFetchOrigin) =>
         trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({
             ...buyQuoteEventProperties(buyQuote),
-            fetchedVia,
+            fetchOrigin,
         }),
-    trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchedVia: QuoteFetchOrigin) => {
+    trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => {
         trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({
             errorMessage,
             assetAmount: assetAmount.toString(),
-            fetchedVia,
+            fetchOrigin,
         });
     },
 };
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 14af57660..06474b69f 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -20,7 +20,7 @@ export const buyQuoteUpdater = {
         options: {
             setPending: boolean;
             dispatchErrors: boolean;
-            fetchedVia: QuoteFetchOrigin;
+            fetchOrigin: QuoteFetchOrigin;
             affiliateInfo?: AffiliateInfo;
         },
     ): Promise<void> => {
@@ -37,7 +37,11 @@ export const buyQuoteUpdater = {
         } catch (error) {
             if (options.dispatchErrors) {
                 dispatch(actions.setQuoteRequestStateFailure());
-                analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, options.fetchedVia);
+                analytics.trackQuoteError(
+                    error.message ? error.message : 'other',
+                    assetUnitAmount,
+                    options.fetchOrigin,
+                );
                 let errorMessage;
                 if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
                     const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
@@ -65,6 +69,6 @@ export const buyQuoteUpdater = {
         errorFlasher.clearError(dispatch);
         // invalidate the last buy quote.
         dispatch(actions.updateLatestBuyQuote(newBuyQuote));
-        analytics.trackQuoteFetched(newBuyQuote, options.fetchedVia);
+        analytics.trackQuoteFetched(newBuyQuote, options.fetchOrigin);
     },
 };
diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts
index 84aeb4dbc..5f7ef55e5 100644
--- a/packages/instant/src/util/heartbeater_factory.ts
+++ b/packages/instant/src/util/heartbeater_factory.ts
@@ -20,7 +20,7 @@ export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): H
     return new Heartbeater(async () => {
         await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, {
             updateSilently: true,
-            fetchedVia: QuoteFetchOrigin.Heartbeat,
+            fetchOrigin: QuoteFetchOrigin.Heartbeat,
         });
     }, shouldPerformImmediatelyOnStart);
 };
-- 
cgit v1.2.3


From 208ee935c843cfff9f0559a4c4058af3908f6261 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 14:17:26 -0800
Subject: Move fetch origin out of options

---
 packages/instant/src/components/zero_ex_instant_provider.tsx |  3 +--
 .../src/containers/selected_erc20_asset_amount_input.ts      |  3 +--
 packages/instant/src/redux/async_data.ts                     |  5 +++--
 packages/instant/src/util/buy_quote_updater.ts               | 10 +++-------
 packages/instant/src/util/heartbeater_factory.ts             | 12 ++++++++----
 5 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index f7880fc12..a4a03bbf4 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -115,9 +115,8 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
         this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS);
         // Trigger first buyquote fetch
         // tslint:disable-next-line:no-floating-promises
-        asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, {
+        asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, QuoteFetchOrigin.Manual, {
             updateSilently: false,
-            fetchOrigin: QuoteFetchOrigin.Manual,
         });
         // warm up the gas price estimator cache just in case we can't
         // grab the gas price estimate when submitting the transaction
diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
index 40e35b575..cb9df527e 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -88,11 +88,10 @@ const mapDispatchToProps = (
             // even if it's debounced, give them the illusion it's loading
             dispatch(actions.setQuoteRequestStatePending());
             // tslint:disable-next-line:no-floating-promises
-            debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, {
+            debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, QuoteFetchOrigin.Manual, {
                 setPending: true,
                 dispatchErrors: true,
                 affiliateInfo,
-                fetchOrigin: QuoteFetchOrigin.Manual,
             });
         }
     },
diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts
index dc73fd9af..9fdcea3ca 100644
--- a/packages/instant/src/redux/async_data.ts
+++ b/packages/instant/src/redux/async_data.ts
@@ -84,7 +84,8 @@ export const asyncData = {
     fetchCurrentBuyQuoteAndDispatchToStore: async (
         state: State,
         dispatch: Dispatch,
-        options: { updateSilently: boolean; fetchOrigin: QuoteFetchOrigin },
+        fetchOrigin: QuoteFetchOrigin,
+        options: { updateSilently: boolean },
     ) => {
         const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
         const assetBuyer = providerState.assetBuyer;
@@ -99,10 +100,10 @@ export const asyncData = {
                 dispatch,
                 selectedAsset as ERC20Asset,
                 selectedAssetUnitAmount,
+                fetchOrigin,
                 {
                     setPending: !options.updateSilently,
                     dispatchErrors: !options.updateSilently,
-                    fetchOrigin: options.fetchOrigin,
                     affiliateInfo,
                 },
             );
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 06474b69f..5685a7d00 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -17,10 +17,10 @@ export const buyQuoteUpdater = {
         dispatch: Dispatch<Action>,
         asset: ERC20Asset,
         assetUnitAmount: BigNumber,
+        fetchOrigin: QuoteFetchOrigin,
         options: {
             setPending: boolean;
             dispatchErrors: boolean;
-            fetchOrigin: QuoteFetchOrigin;
             affiliateInfo?: AffiliateInfo;
         },
     ): Promise<void> => {
@@ -37,11 +37,7 @@ export const buyQuoteUpdater = {
         } catch (error) {
             if (options.dispatchErrors) {
                 dispatch(actions.setQuoteRequestStateFailure());
-                analytics.trackQuoteError(
-                    error.message ? error.message : 'other',
-                    assetUnitAmount,
-                    options.fetchOrigin,
-                );
+                analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, fetchOrigin);
                 let errorMessage;
                 if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
                     const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
@@ -69,6 +65,6 @@ export const buyQuoteUpdater = {
         errorFlasher.clearError(dispatch);
         // invalidate the last buy quote.
         dispatch(actions.updateLatestBuyQuote(newBuyQuote));
-        analytics.trackQuoteFetched(newBuyQuote, options.fetchOrigin);
+        analytics.trackQuoteFetched(newBuyQuote, fetchOrigin);
     },
 };
diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts
index 5f7ef55e5..cf29bf3ea 100644
--- a/packages/instant/src/util/heartbeater_factory.ts
+++ b/packages/instant/src/util/heartbeater_factory.ts
@@ -18,9 +18,13 @@ export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): He
 export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
     const { store, shouldPerformImmediatelyOnStart } = options;
     return new Heartbeater(async () => {
-        await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, {
-            updateSilently: true,
-            fetchOrigin: QuoteFetchOrigin.Heartbeat,
-        });
+        await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(
+            store.getState(),
+            store.dispatch,
+            QuoteFetchOrigin.Heartbeat,
+            {
+                updateSilently: true,
+            },
+        );
     }, shouldPerformImmediatelyOnStart);
 };
-- 
cgit v1.2.3


From b9c983b4d691e58894b8b47f8e5952fdfcc275f9 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Wed, 28 Nov 2018 14:24:02 -0800
Subject: Use base unit value

---
 packages/instant/src/util/buy_quote_updater.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 5685a7d00..c1899f8c1 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -37,7 +37,7 @@ export const buyQuoteUpdater = {
         } catch (error) {
             if (options.dispatchErrors) {
                 dispatch(actions.setQuoteRequestStateFailure());
-                analytics.trackQuoteError(error.message ? error.message : 'other', assetUnitAmount, fetchOrigin);
+                analytics.trackQuoteError(error.message ? error.message : 'other', baseUnitValue, fetchOrigin);
                 let errorMessage;
                 if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
                     const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
-- 
cgit v1.2.3


From 77d6594ecb78a85d51a8aef39744ae62e4085bbc Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 1 Nov 2018 15:45:38 +0100
Subject: Plugging away at encoder

---
 packages/order-utils/test/abi_encoder.ts | 483 +++++++++++++++++++++++++++++++
 1 file changed, 483 insertions(+)
 create mode 100644 packages/order-utils/test/abi_encoder.ts

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
new file mode 100644
index 000000000..46449662a
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -0,0 +1,483 @@
+import * as chai from 'chai';
+import 'mocha';
+import ethUtil = require('ethereumjs-util');
+
+var _ = require('lodash');
+
+import { assert } from '@0x/order-utils/src/assert';
+
+import { chaiSetup } from '@0x/order-utils/test/utils/chai_setup';
+import { web3Wrapper } from '@0x/order-utils/test/utils/web3_wrapper';
+
+import { MethodAbi, DataItem } from 'ethereum-types';
+import { throwError } from 'ethers/errors';
+
+import { BigNumber } from '@0x/utils';
+import { MethodNotFound } from 'json-rpc-error';
+import { power } from 'js-combinatorics';
+
+const simpleAbi = {
+    name: 'SimpleAbi',
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'greg',
+                    type: 'uint256',
+                },
+                {
+                    name: 'gregStr',
+                    type: 'string',
+                },
+            ],
+        },
+    ],
+} as MethodAbi;
+const fillOrderAbi = {
+    constant: false,
+    inputs: [
+        {
+            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: 'order',
+            type: 'tuple',
+        },
+        {
+            name: 'takerAssetFillAmount',
+            type: 'uint256',
+        },
+        {
+            name: 'salt',
+            type: 'uint256',
+        },
+        {
+            name: 'orderSignature',
+            type: 'bytes',
+        },
+        {
+            name: 'takerSignature',
+            type: 'bytes',
+        },
+    ],
+    name: 'fillOrder',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+namespace AbiEncoder {
+    class Memory {}
+
+    class Word {}
+
+    abstract class DataType {
+        private dataItem: DataItem;
+        private hexValue: string;
+
+        constructor(dataItem: DataItem) {
+            this.dataItem = dataItem;
+            this.hexValue = '0x';
+        }
+
+        protected assignHexValue(hexValue: string) {
+            this.hexValue = hexValue;
+        }
+
+        public getHexValue(): string {
+            return this.hexValue;
+        }
+
+        public abstract assignValue(value: any): void;
+
+        // abstract match(type: string): Bool;
+    }
+
+    class Calldata {}
+
+    abstract class StaticDataType extends DataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+        }
+    }
+
+    abstract class DynamicDataType extends DataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+        }
+    }
+
+    class Address extends StaticDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'address';
+        }
+    }
+
+    class Bool extends StaticDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'bool';
+        }
+    }
+
+    class Int extends StaticDataType {
+        static matcher = RegExp(
+            '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+        );
+
+        static DEFAULT_WIDTH = new BigNumber(1);
+        width: BigNumber = Byte.DEFAULT_WIDTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = Byte.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.width = new BigNumber(matches[1], 10);
+            }
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class UInt extends StaticDataType {
+        static matcher = RegExp(
+            '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+        );
+
+        static DEFAULT_WIDTH: number = 1;
+        width: number = UInt.DEFAULT_WIDTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = Byte.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.width = parseInt(matches[1]);
+            }
+        }
+
+        public getMaxValue() {
+            return new BigNumber(2).toPower(this.width - 1);
+        }
+
+        public assignValue(value: BigNumber) {
+            if (value > this.getMaxValue()) {
+                throw 1;
+            }
+
+            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
+            const encodedValue = ethUtil.bufferToHex(valueBuf);
+
+            this.assignHexValue(encodedValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class Byte extends StaticDataType {
+        static matcher = RegExp(
+            '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+        );
+
+        static DEFAULT_WIDTH = new BigNumber(1);
+        width: BigNumber = Byte.DEFAULT_WIDTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = Byte.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.width = new BigNumber(matches[1], 10);
+            }
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class Tuple extends DynamicDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'tuple';
+        }
+    }
+
+    class Bytes extends StaticDataType {
+        static UNDEFINED_LENGTH = new BigNumber(-1);
+        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'bytes';
+        }
+    }
+
+    class SolArray extends DynamicDataType {
+        static matcher = RegExp('^.+\\[([0-9]d*)\\]$');
+        static UNDEFINED_LENGTH = new BigNumber(-1);
+        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = SolArray.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.length = new BigNumber(matches[1], 10);
+            }
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class SolString extends DynamicDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(SolString.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
+            const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+            const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
+
+            this.assignHexValue(encodedValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'string';
+        }
+    }
+
+    /* TODO
+    class Fixed extends StaticDataType {}
+
+    class UFixed extends StaticDataType {}*/
+
+    class Pointer extends StaticDataType {
+        destDataType: DynamicDataType;
+        static metaDataItem = { name: '[ptr]', type: '[ptr]' } as DataItem;
+
+        constructor(destDataType: DynamicDataType) {
+            super(Pointer.metaDataItem);
+            this.destDataType = destDataType;
+        }
+
+        public assignValue(destDataType: DynamicDataType) {
+            this.destDataType = destDataType;
+        }
+    }
+
+    class DataTypeFactory {
+        public static mapDataItemToDataType(dataItem: DataItem): DataType {
+            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+            if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
+            if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
+            if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
+            if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
+            if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
+            if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
+            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+            if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
+            if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
+            //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
+            //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
+
+            throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+        }
+
+        public static create(dataItem: DataItem): DataType {
+            const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
+            if (dataType instanceof StaticDataType) {
+                return dataType;
+            } else if (dataType instanceof DynamicDataType) {
+                const pointer = new Pointer(dataType);
+                return pointer;
+            }
+
+            throw new Error(`Unrecognized instance type: '${dataType}'`);
+        }
+    }
+
+    export class Method {
+        name: string;
+        params: DataType[];
+
+        constructor(abi: MethodAbi) {
+            // super();
+            this.name = abi.name;
+            this.params = [];
+
+            _.each(abi.inputs, function(this: Method, input: DataItem) {
+                this.params.push(DataTypeFactory.create(input));
+            });
+        }
+
+        encode(args: any[]): string {
+            //const calldata = new Calldata(this.name, this.params.length);
+            let params = this.params;
+            _.each(params, function(args: any[], i: number, param: DataType) {
+                param.assignValue(args[i]);
+                console.log(param.getHexValue());
+                //param.encodeToCalldata(calldata);
+            });
+
+            return '';
+
+            //return calldata.getRaw();
+        }
+
+        /*
+        encodeOptimized(args: any[]): string {
+            const calldata = new Memory();
+            // Assign values
+            optimizableParams : StaticDataType = [];
+            _.each(this.params, function(args: any[], i: number, param: DataType) {
+                param.assignValue(args[i]);
+                if (param instanceof DynamicDataType) {
+
+                }
+            });
+
+            // Find non-parameter leaves
+
+
+            return '';
+        } */
+
+        /*
+        decode(rawCalldata: string): any[] {
+            const calldata = new Calldata(this.name, this.params.length);
+            calldata.assignRaw(rawCalldata);
+            let args: any[];
+            let params = this.params;
+            _.each(params, function(args: any[], i: number, param: DataType) {
+                param.decodeFromCalldata(calldata);
+                args.push(param.getValue());
+            });
+
+            return args;
+        }*/
+    }
+}
+
+describe.only('ABI Encoder', () => {
+    describe.only('Just a Greg, Eh', () => {
+        it.only('Yessir', async () => {
+            const method = new AbiEncoder.Method(simpleAbi);
+            method.encode([new BigNumber(5), 'five']);
+            expect(true).to.be.true();
+        });
+    });
+});
-- 
cgit v1.2.3


From 79126f3b4a83d9cf58e5a7935051820ae5e1a8e0 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 11:13:56 -0800
Subject: renamed

---
 packages/order-utils/test/abi_encoder.ts      | 483 --------------------------
 packages/order-utils/test/abi_encoder_test.ts | 479 +++++++++++++++++++++++++
 2 files changed, 479 insertions(+), 483 deletions(-)
 delete mode 100644 packages/order-utils/test/abi_encoder.ts
 create mode 100644 packages/order-utils/test/abi_encoder_test.ts

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
deleted file mode 100644
index 46449662a..000000000
--- a/packages/order-utils/test/abi_encoder.ts
+++ /dev/null
@@ -1,483 +0,0 @@
-import * as chai from 'chai';
-import 'mocha';
-import ethUtil = require('ethereumjs-util');
-
-var _ = require('lodash');
-
-import { assert } from '@0x/order-utils/src/assert';
-
-import { chaiSetup } from '@0x/order-utils/test/utils/chai_setup';
-import { web3Wrapper } from '@0x/order-utils/test/utils/web3_wrapper';
-
-import { MethodAbi, DataItem } from 'ethereum-types';
-import { throwError } from 'ethers/errors';
-
-import { BigNumber } from '@0x/utils';
-import { MethodNotFound } from 'json-rpc-error';
-import { power } from 'js-combinatorics';
-
-const simpleAbi = {
-    name: 'SimpleAbi',
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'greg',
-                    type: 'uint256',
-                },
-                {
-                    name: 'gregStr',
-                    type: 'string',
-                },
-            ],
-        },
-    ],
-} as MethodAbi;
-const fillOrderAbi = {
-    constant: false,
-    inputs: [
-        {
-            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: 'order',
-            type: 'tuple',
-        },
-        {
-            name: 'takerAssetFillAmount',
-            type: 'uint256',
-        },
-        {
-            name: 'salt',
-            type: 'uint256',
-        },
-        {
-            name: 'orderSignature',
-            type: 'bytes',
-        },
-        {
-            name: 'takerSignature',
-            type: 'bytes',
-        },
-    ],
-    name: 'fillOrder',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-namespace AbiEncoder {
-    class Memory {}
-
-    class Word {}
-
-    abstract class DataType {
-        private dataItem: DataItem;
-        private hexValue: string;
-
-        constructor(dataItem: DataItem) {
-            this.dataItem = dataItem;
-            this.hexValue = '0x';
-        }
-
-        protected assignHexValue(hexValue: string) {
-            this.hexValue = hexValue;
-        }
-
-        public getHexValue(): string {
-            return this.hexValue;
-        }
-
-        public abstract assignValue(value: any): void;
-
-        // abstract match(type: string): Bool;
-    }
-
-    class Calldata {}
-
-    abstract class StaticDataType extends DataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-        }
-    }
-
-    abstract class DynamicDataType extends DataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-        }
-    }
-
-    class Address extends StaticDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'address';
-        }
-    }
-
-    class Bool extends StaticDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'bool';
-        }
-    }
-
-    class Int extends StaticDataType {
-        static matcher = RegExp(
-            '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-        );
-
-        static DEFAULT_WIDTH = new BigNumber(1);
-        width: BigNumber = Byte.DEFAULT_WIDTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = Byte.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
-                this.width = new BigNumber(matches[1], 10);
-            }
-        }
-
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    class UInt extends StaticDataType {
-        static matcher = RegExp(
-            '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-        );
-
-        static DEFAULT_WIDTH: number = 1;
-        width: number = UInt.DEFAULT_WIDTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = Byte.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
-                this.width = parseInt(matches[1]);
-            }
-        }
-
-        public getMaxValue() {
-            return new BigNumber(2).toPower(this.width - 1);
-        }
-
-        public assignValue(value: BigNumber) {
-            if (value > this.getMaxValue()) {
-                throw 1;
-            }
-
-            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
-            const encodedValue = ethUtil.bufferToHex(valueBuf);
-
-            this.assignHexValue(encodedValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    class Byte extends StaticDataType {
-        static matcher = RegExp(
-            '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
-        );
-
-        static DEFAULT_WIDTH = new BigNumber(1);
-        width: BigNumber = Byte.DEFAULT_WIDTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = Byte.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
-                this.width = new BigNumber(matches[1], 10);
-            }
-        }
-
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    class Tuple extends DynamicDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'tuple';
-        }
-    }
-
-    class Bytes extends StaticDataType {
-        static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = SolArray.UNDEFINED_LENGTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'bytes';
-        }
-    }
-
-    class SolArray extends DynamicDataType {
-        static matcher = RegExp('^.+\\[([0-9]d*)\\]$');
-        static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = SolArray.UNDEFINED_LENGTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = SolArray.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
-                this.length = new BigNumber(matches[1], 10);
-            }
-        }
-
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    class SolString extends DynamicDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(SolString.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
-            const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
-            const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
-
-            this.assignHexValue(encodedValue);
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'string';
-        }
-    }
-
-    /* TODO
-    class Fixed extends StaticDataType {}
-
-    class UFixed extends StaticDataType {}*/
-
-    class Pointer extends StaticDataType {
-        destDataType: DynamicDataType;
-        static metaDataItem = { name: '[ptr]', type: '[ptr]' } as DataItem;
-
-        constructor(destDataType: DynamicDataType) {
-            super(Pointer.metaDataItem);
-            this.destDataType = destDataType;
-        }
-
-        public assignValue(destDataType: DynamicDataType) {
-            this.destDataType = destDataType;
-        }
-    }
-
-    class DataTypeFactory {
-        public static mapDataItemToDataType(dataItem: DataItem): DataType {
-            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-            if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
-            if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-            if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
-            if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
-            if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
-            if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
-            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-            if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
-            if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
-            //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
-            //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
-
-            throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-        }
-
-        public static create(dataItem: DataItem): DataType {
-            const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
-            if (dataType instanceof StaticDataType) {
-                return dataType;
-            } else if (dataType instanceof DynamicDataType) {
-                const pointer = new Pointer(dataType);
-                return pointer;
-            }
-
-            throw new Error(`Unrecognized instance type: '${dataType}'`);
-        }
-    }
-
-    export class Method {
-        name: string;
-        params: DataType[];
-
-        constructor(abi: MethodAbi) {
-            // super();
-            this.name = abi.name;
-            this.params = [];
-
-            _.each(abi.inputs, function(this: Method, input: DataItem) {
-                this.params.push(DataTypeFactory.create(input));
-            });
-        }
-
-        encode(args: any[]): string {
-            //const calldata = new Calldata(this.name, this.params.length);
-            let params = this.params;
-            _.each(params, function(args: any[], i: number, param: DataType) {
-                param.assignValue(args[i]);
-                console.log(param.getHexValue());
-                //param.encodeToCalldata(calldata);
-            });
-
-            return '';
-
-            //return calldata.getRaw();
-        }
-
-        /*
-        encodeOptimized(args: any[]): string {
-            const calldata = new Memory();
-            // Assign values
-            optimizableParams : StaticDataType = [];
-            _.each(this.params, function(args: any[], i: number, param: DataType) {
-                param.assignValue(args[i]);
-                if (param instanceof DynamicDataType) {
-
-                }
-            });
-
-            // Find non-parameter leaves
-
-
-            return '';
-        } */
-
-        /*
-        decode(rawCalldata: string): any[] {
-            const calldata = new Calldata(this.name, this.params.length);
-            calldata.assignRaw(rawCalldata);
-            let args: any[];
-            let params = this.params;
-            _.each(params, function(args: any[], i: number, param: DataType) {
-                param.decodeFromCalldata(calldata);
-                args.push(param.getValue());
-            });
-
-            return args;
-        }*/
-    }
-}
-
-describe.only('ABI Encoder', () => {
-    describe.only('Just a Greg, Eh', () => {
-        it.only('Yessir', async () => {
-            const method = new AbiEncoder.Method(simpleAbi);
-            method.encode([new BigNumber(5), 'five']);
-            expect(true).to.be.true();
-        });
-    });
-});
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
new file mode 100644
index 000000000..87e1e7fba
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -0,0 +1,479 @@
+import * as chai from 'chai';
+import 'mocha';
+import ethUtil = require('ethereumjs-util');
+
+var _ = require('lodash');
+
+// import { assert } from '@0x/order-utils/src/assert';
+
+import { chaiSetup } from './utils/chai_setup';
+
+import { MethodAbi, DataItem } from 'ethereum-types';
+
+import { BigNumber } from '@0x/utils';
+
+const simpleAbi = {
+    name: 'SimpleAbi',
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'greg',
+                    type: 'uint256',
+                },
+                {
+                    name: 'gregStr',
+                    type: 'string',
+                },
+            ],
+        },
+    ],
+} as MethodAbi;
+const fillOrderAbi = {
+    constant: false,
+    inputs: [
+        {
+            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: 'order',
+            type: 'tuple',
+        },
+        {
+            name: 'takerAssetFillAmount',
+            type: 'uint256',
+        },
+        {
+            name: 'salt',
+            type: 'uint256',
+        },
+        {
+            name: 'orderSignature',
+            type: 'bytes',
+        },
+        {
+            name: 'takerSignature',
+            type: 'bytes',
+        },
+    ],
+    name: 'fillOrder',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+namespace AbiEncoder {
+    class Memory {}
+
+    class Word {}
+
+    abstract class DataType {
+        private dataItem: DataItem;
+        private hexValue: string;
+
+        constructor(dataItem: DataItem) {
+            this.dataItem = dataItem;
+            this.hexValue = '0x';
+        }
+
+        protected assignHexValue(hexValue: string) {
+            this.hexValue = hexValue;
+        }
+
+        public getHexValue(): string {
+            return this.hexValue;
+        }
+
+        public abstract assignValue(value: any): void;
+
+        // abstract match(type: string): Bool;
+    }
+
+    class Calldata {}
+
+    abstract class StaticDataType extends DataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+        }
+    }
+
+    abstract class DynamicDataType extends DataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+        }
+    }
+
+    class Address extends StaticDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'address';
+        }
+    }
+
+    class Bool extends StaticDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'bool';
+        }
+    }
+
+    class Int extends StaticDataType {
+        static matcher = RegExp(
+            '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+        );
+
+        static DEFAULT_WIDTH = new BigNumber(1);
+        width: BigNumber = Byte.DEFAULT_WIDTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = Byte.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.width = new BigNumber(matches[1], 10);
+            }
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class UInt extends StaticDataType {
+        static matcher = RegExp(
+            '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+        );
+
+        static DEFAULT_WIDTH: number = 1;
+        width: number = UInt.DEFAULT_WIDTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = Byte.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.width = parseInt(matches[1]);
+            }
+        }
+
+        public getMaxValue() {
+            return new BigNumber(2).toPower(this.width - 1);
+        }
+
+        public assignValue(value: BigNumber) {
+            if (value > this.getMaxValue()) {
+                throw 1;
+            }
+
+            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
+            const encodedValue = ethUtil.bufferToHex(valueBuf);
+
+            this.assignHexValue(encodedValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class Byte extends StaticDataType {
+        static matcher = RegExp(
+            '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+        );
+
+        static DEFAULT_WIDTH = new BigNumber(1);
+        width: BigNumber = Byte.DEFAULT_WIDTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = Byte.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.width = new BigNumber(matches[1], 10);
+            }
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class Tuple extends DynamicDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'tuple';
+        }
+    }
+
+    class Bytes extends StaticDataType {
+        static UNDEFINED_LENGTH = new BigNumber(-1);
+        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'bytes';
+        }
+    }
+
+    class SolArray extends DynamicDataType {
+        static matcher = RegExp('^.+\\[([0-9]d*)\\]$');
+        static UNDEFINED_LENGTH = new BigNumber(-1);
+        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            const matches = SolArray.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches !== null && matches.length === 1) {
+                this.length = new BigNumber(matches[1], 10);
+            }
+        }
+
+        public assignValue(value: string) {
+            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            //this.assignHexValue(hexValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
+        }
+    }
+
+    class SolString extends DynamicDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(SolString.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
+            const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+            const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
+
+            this.assignHexValue(encodedValue);
+        }
+
+        public static matchGrammar(type: string): boolean {
+            return type === 'string';
+        }
+    }
+
+    /* TODO
+    class Fixed extends StaticDataType {}
+
+    class UFixed extends StaticDataType {}*/
+
+    class Pointer extends StaticDataType {
+        destDataType: DynamicDataType;
+        static metaDataItem = { name: '[ptr]', type: '[ptr]' } as DataItem;
+
+        constructor(destDataType: DynamicDataType) {
+            super(Pointer.metaDataItem);
+            this.destDataType = destDataType;
+        }
+
+        public assignValue(destDataType: DynamicDataType) {
+            this.destDataType = destDataType;
+        }
+    }
+
+    class DataTypeFactory {
+        public static mapDataItemToDataType(dataItem: DataItem): DataType {
+            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+            if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
+            if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
+            if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
+            if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
+            if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
+            if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
+            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+            if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
+            if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
+            //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
+            //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
+
+            throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+        }
+
+        public static create(dataItem: DataItem): DataType {
+            const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
+            if (dataType instanceof StaticDataType) {
+                return dataType;
+            } else if (dataType instanceof DynamicDataType) {
+                const pointer = new Pointer(dataType);
+                return pointer;
+            }
+
+            throw new Error(`Unrecognized instance type: '${dataType}'`);
+        }
+    }
+
+    export class Method {
+        name: string;
+        params: DataType[];
+
+        constructor(abi: MethodAbi) {
+            // super();
+            this.name = abi.name;
+            this.params = [];
+
+            _.each(abi.inputs, function(this: Method, input: DataItem) {
+                this.params.push(DataTypeFactory.create(input));
+            });
+        }
+
+        encode(args: any[]): string {
+            //const calldata = new Calldata(this.name, this.params.length);
+            let params = this.params;
+            _.each(params, function(args: any[], i: number, param: DataType) {
+                param.assignValue(args[i]);
+                console.log(param.getHexValue());
+                //param.encodeToCalldata(calldata);
+            });
+
+            return '';
+
+            //return calldata.getRaw();
+        }
+
+        /*
+        encodeOptimized(args: any[]): string {
+            const calldata = new Memory();
+            // Assign values
+            optimizableParams : StaticDataType = [];
+            _.each(this.params, function(args: any[], i: number, param: DataType) {
+                param.assignValue(args[i]);
+                if (param instanceof DynamicDataType) {
+
+                }
+            });
+
+            // Find non-parameter leaves
+
+
+            return '';
+        } */
+
+        /*
+        decode(rawCalldata: string): any[] {
+            const calldata = new Calldata(this.name, this.params.length);
+            calldata.assignRaw(rawCalldata);
+            let args: any[];
+            let params = this.params;
+            _.each(params, function(args: any[], i: number, param: DataType) {
+                param.decodeFromCalldata(calldata);
+                args.push(param.getValue());
+            });
+
+            return args;
+        }*/
+    }
+}
+
+describe.only('ABI Encoder', () => {
+    describe.only('Just a Greg, Eh', () => {
+        it.only('Yessir', async () => {
+            const method = new AbiEncoder.Method(simpleAbi);
+            method.encode([new BigNumber(5), 'five']);
+            expect(true).to.be.true();
+        });
+    });
+});
-- 
cgit v1.2.3


From a1cff862c979d013f3f56af55c324fe38b588473 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 11:32:29 -0800
Subject: Fixed width parsing for UINT

---
 packages/order-utils/test/abi_encoder_test.ts | 43 ++++++++++++++++-----------
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 87e1e7fba..f6f7fd93e 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -13,22 +13,24 @@ import { MethodAbi, DataItem } from 'ethereum-types';
 import { BigNumber } from '@0x/utils';
 
 const simpleAbi = {
-    name: 'SimpleAbi',
+    constant: false,
     inputs: [
         {
-            components: [
-                {
-                    name: 'greg',
-                    type: 'uint256',
-                },
-                {
-                    name: 'gregStr',
-                    type: 'string',
-                },
-            ],
+            name: 'greg',
+            type: 'uint208',
+        },
+        {
+            name: 'gregStr',
+            type: 'string',
         },
     ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
 } as MethodAbi;
+
 const fillOrderAbi = {
     constant: false,
     inputs: [
@@ -198,7 +200,7 @@ namespace AbiEncoder {
             super(dataItem);
             const matches = Byte.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
+            if (matches !== null && matches.length === 2) {
                 this.width = new BigNumber(matches[1], 10);
             }
         }
@@ -218,16 +220,20 @@ namespace AbiEncoder {
             '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
         );
 
-        static DEFAULT_WIDTH: number = 1;
+        static DEFAULT_WIDTH: number = 256;
         width: number = UInt.DEFAULT_WIDTH;
 
         constructor(dataItem: DataItem) {
             super(dataItem);
-            const matches = Byte.matcher.exec(dataItem.type);
+            const matches = UInt.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
+            console.log(JSON.stringify(matches));
+            if (matches !== null && matches.length === 2) {
                 this.width = parseInt(matches[1]);
+            } else {
+                this.width = 256;
             }
+            console.log('Width = ' + this.width);
         }
 
         public getMaxValue() {
@@ -262,7 +268,7 @@ namespace AbiEncoder {
             super(dataItem);
             const matches = Byte.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
+            if (matches !== null && matches.length === 2) {
                 this.width = new BigNumber(matches[1], 10);
             }
         }
@@ -377,6 +383,8 @@ namespace AbiEncoder {
 
     class DataTypeFactory {
         public static mapDataItemToDataType(dataItem: DataItem): DataType {
+            console.log(`Type: ${dataItem.type}`);
+
             if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
             if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
             if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
@@ -415,7 +423,8 @@ namespace AbiEncoder {
             this.name = abi.name;
             this.params = [];
 
-            _.each(abi.inputs, function(this: Method, input: DataItem) {
+            _.each(abi.inputs, (input: DataItem) => {
+                console.log('--input--\n', input, '--end input--');
                 this.params.push(DataTypeFactory.create(input));
             });
         }
-- 
cgit v1.2.3


From 331cca37e2bce35a1351f75a85b97ab60dfad196 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 13:17:15 -0800
Subject: works for assigning value to uint

---
 packages/order-utils/test/abi_encoder_test.ts | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index f6f7fd93e..6b32d59aa 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -227,25 +227,29 @@ namespace AbiEncoder {
             super(dataItem);
             const matches = UInt.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            console.log(JSON.stringify(matches));
             if (matches !== null && matches.length === 2) {
                 this.width = parseInt(matches[1]);
             } else {
                 this.width = 256;
             }
-            console.log('Width = ' + this.width);
         }
 
-        public getMaxValue() {
+        public getMaxValue(): BigNumber {
             return new BigNumber(2).toPower(this.width - 1);
         }
 
         public assignValue(value: BigNumber) {
-            if (value > this.getMaxValue()) {
-                throw 1;
+            console.log(JSON.stringify(value));
+            console.log(JSON.stringify(this.getMaxValue()));
+            if (value.greaterThan(this.getMaxValue())) {
+                throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+            } else if (value.lessThan(0)) {
+                throw `tried to assign value of ${value} to an unsigned integer.`;
             }
 
-            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
+            const hexBase = 16;
+            const evmWordWidth = 32;
+            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
             const encodedValue = ethUtil.bufferToHex(valueBuf);
 
             this.assignHexValue(encodedValue);
@@ -424,7 +428,6 @@ namespace AbiEncoder {
             this.params = [];
 
             _.each(abi.inputs, (input: DataItem) => {
-                console.log('--input--\n', input, '--end input--');
                 this.params.push(DataTypeFactory.create(input));
             });
         }
@@ -432,7 +435,9 @@ namespace AbiEncoder {
         encode(args: any[]): string {
             //const calldata = new Calldata(this.name, this.params.length);
             let params = this.params;
-            _.each(params, function(args: any[], i: number, param: DataType) {
+            _.each(params, (param: DataType, i: number) => {
+                console.log('param:\n', param, '\n--end--\n');
+                console.log('arg:\n', args[i], '\n--end\n');
                 param.assignValue(args[i]);
                 console.log(param.getHexValue());
                 //param.encodeToCalldata(calldata);
-- 
cgit v1.2.3


From bce62056d953abc424a5171adbaff1641f8f6626 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 13:28:59 -0800
Subject: cleaner name/type for pointer

---
 packages/order-utils/test/abi_encoder_test.ts | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 6b32d59aa..4b8ed48cc 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -137,6 +137,10 @@ namespace AbiEncoder {
             return this.hexValue;
         }
 
+        public getDataItem(): DataItem {
+            return this.dataItem;
+        }
+
         public abstract assignValue(value: any): void;
 
         // abstract match(type: string): Bool;
@@ -373,15 +377,25 @@ namespace AbiEncoder {
 
     class Pointer extends StaticDataType {
         destDataType: DynamicDataType;
-        static metaDataItem = { name: '[ptr]', type: '[ptr]' } as DataItem;
 
         constructor(destDataType: DynamicDataType) {
-            super(Pointer.metaDataItem);
+            const destDataItem = destDataType.getDataItem();
+            const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
+            super(dataItem);
             this.destDataType = destDataType;
         }
 
+        /*
         public assignValue(destDataType: DynamicDataType) {
             this.destDataType = destDataType;
+        }*/
+
+        public assignValue(value: any) {
+            this.destDataType.assignValue(value);
+        }
+
+        public getHexValue(): string {
+            return this.destDataType.getHexValue();
         }
     }
 
-- 
cgit v1.2.3


From d5dbd8cd686195e38c3c4a0857e3231e0a026287 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 13:47:44 -0800
Subject: tests for String

---
 packages/order-utils/test/abi_encoder_test.ts | 59 +++++++++++++++++++--------
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 4b8ed48cc..0366ddfcc 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -120,7 +120,7 @@ namespace AbiEncoder {
 
     class Word {}
 
-    abstract class DataType {
+    export abstract class DataType {
         private dataItem: DataItem;
         private hexValue: string;
 
@@ -148,19 +148,19 @@ namespace AbiEncoder {
 
     class Calldata {}
 
-    abstract class StaticDataType extends DataType {
+    export abstract class StaticDataType extends DataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
         }
     }
 
-    abstract class DynamicDataType extends DataType {
+    export abstract class DynamicDataType extends DataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
         }
     }
 
-    class Address extends StaticDataType {
+    export class Address extends StaticDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
             expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
@@ -176,7 +176,7 @@ namespace AbiEncoder {
         }
     }
 
-    class Bool extends StaticDataType {
+    export class Bool extends StaticDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
             expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
@@ -192,7 +192,7 @@ namespace AbiEncoder {
         }
     }
 
-    class Int extends StaticDataType {
+    export class Int extends StaticDataType {
         static matcher = RegExp(
             '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
         );
@@ -219,7 +219,7 @@ namespace AbiEncoder {
         }
     }
 
-    class UInt extends StaticDataType {
+    export class UInt extends StaticDataType {
         static matcher = RegExp(
             '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
         );
@@ -264,7 +264,7 @@ namespace AbiEncoder {
         }
     }
 
-    class Byte extends StaticDataType {
+    export class Byte extends StaticDataType {
         static matcher = RegExp(
             '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
         );
@@ -291,7 +291,7 @@ namespace AbiEncoder {
         }
     }
 
-    class Tuple extends DynamicDataType {
+    export class Tuple extends DynamicDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
             expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
@@ -307,7 +307,7 @@ namespace AbiEncoder {
         }
     }
 
-    class Bytes extends StaticDataType {
+    export class Bytes extends StaticDataType {
         static UNDEFINED_LENGTH = new BigNumber(-1);
         length: BigNumber = SolArray.UNDEFINED_LENGTH;
 
@@ -326,7 +326,7 @@ namespace AbiEncoder {
         }
     }
 
-    class SolArray extends DynamicDataType {
+    export class SolArray extends DynamicDataType {
         static matcher = RegExp('^.+\\[([0-9]d*)\\]$');
         static UNDEFINED_LENGTH = new BigNumber(-1);
         length: BigNumber = SolArray.UNDEFINED_LENGTH;
@@ -350,14 +350,16 @@ namespace AbiEncoder {
         }
     }
 
-    class SolString extends DynamicDataType {
+    export class SolString extends DynamicDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
             expect(SolString.matchGrammar(dataItem.type)).to.be.true();
         }
 
         public assignValue(value: string) {
-            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), 32);
+            const wordsForValue = Math.ceil(value.length / 32);
+            const paddedBytesForValue = wordsForValue * 32;
+            const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
             const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
             const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
             const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
@@ -375,7 +377,7 @@ namespace AbiEncoder {
 
     class UFixed extends StaticDataType {}*/
 
-    class Pointer extends StaticDataType {
+    export class Pointer extends StaticDataType {
         destDataType: DynamicDataType;
 
         constructor(destDataType: DynamicDataType) {
@@ -399,7 +401,7 @@ namespace AbiEncoder {
         }
     }
 
-    class DataTypeFactory {
+    export class DataTypeFactory {
         public static mapDataItemToDataType(dataItem: DataItem): DataType {
             console.log(`Type: ${dataItem.type}`);
 
@@ -497,11 +499,34 @@ namespace AbiEncoder {
 }
 
 describe.only('ABI Encoder', () => {
-    describe.only('Just a Greg, Eh', () => {
-        it.only('Yessir', async () => {
+    describe('Just a Greg, Eh', () => {
+        it('Yessir', async () => {
             const method = new AbiEncoder.Method(simpleAbi);
             method.encode([new BigNumber(5), 'five']);
             expect(true).to.be.true();
         });
     });
+
+    describe('String', () => {
+        const testStringDataItem = { name: 'testString', type: 'string' };
+        it('Less than 32 bytes', async () => {
+            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+            stringDataType.assignValue('five');
+            const expectedAbiEncodedString =
+                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+
+            console.log(stringDataType.getHexValue());
+            console.log(expectedAbiEncodedString);
+            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+        });
+
+        it('Greater than 32 bytes', async () => {
+            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+            const testValue = 'a'.repeat(40);
+            stringDataType.assignValue(testValue);
+            const expectedAbiEncodedString =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+        });
+    });
 });
-- 
cgit v1.2.3


From 96bcc7e33281a3a7831e92dad65de5303ac39523 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 16:33:25 -0800
Subject: Going towards first calldata impl

---
 packages/order-utils/test/abi_encoder_test.ts | 265 ++++++++++++++++++++++++--
 1 file changed, 250 insertions(+), 15 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 0366ddfcc..7e12dfee6 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -11,13 +11,14 @@ import { chaiSetup } from './utils/chai_setup';
 import { MethodAbi, DataItem } from 'ethereum-types';
 
 import { BigNumber } from '@0x/utils';
+import { assert } from '@0x/order-utils/src/assert';
 
 const simpleAbi = {
     constant: false,
     inputs: [
         {
             name: 'greg',
-            type: 'uint208',
+            type: 'uint256',
         },
         {
             name: 'gregStr',
@@ -116,17 +117,138 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 namespace AbiEncoder {
-    class Memory {}
+    class Word {
+        private value: string;
+
+        constructor(value?: string) {
+            if (value === undefined) {
+                this.value = '';
+            } else {
+                this.value = value;
+            }
+        }
+
+        public set(value: string) {
+            if (value.length !== 64) {
+                throw `Tried to create word that is not 32 bytes: ${value}`;
+            }
 
-    class Word {}
+            this.value = value;
+        }
+
+        public get(): string {
+            return this.value;
+        }
+
+        public getAsHex(): string {
+            return `0x${this.value}`;
+        }
+    }
+
+    enum CalldataSection {
+        NONE,
+        PARAMS,
+        DATA,
+    }
+
+    class Memblock {
+        private dataType: DataType;
+        private location: { calldataSection: CalldataSection; offset: BigNumber };
+
+        constructor(dataType: DataType) {
+            this.dataType = dataType;
+            this.location = {
+                calldataSection: CalldataSection.NONE,
+                offset: new BigNumber(0),
+            };
+        }
+
+        public getSize(): BigNumber {
+            return new BigNumber(ethUtil.toBuffer(this.dataType.getHexValue()).byteLength);
+        }
+
+        public assignLocation(calldataSection: CalldataSection, offset: BigNumber) {
+            this.location.calldataSection = calldataSection;
+            this.location.offset = offset;
+        }
+
+        public get(): string {
+            return ethUtil.stripHexPrefix(this.dataType.getHexValue());
+        }
+    }
+
+    interface BindList {
+        [key: string]: Memblock;
+    }
+
+    class Calldata {
+        private selector: string;
+        private params: Memblock[];
+        private data: Memblock[];
+        private dataOffset: BigNumber;
+        private currentDataOffset: BigNumber;
+        private currentParamOffset: BigNumber;
+        private bindList: BindList;
+
+        constructor(selector: string, nParams: number) {
+            this.selector = selector;
+            console.log(this.selector);
+            this.params = [];
+            this.data = [];
+            const evmWordSize = 32;
+            this.dataOffset = new BigNumber(nParams).times(evmWordSize);
+            this.currentDataOffset = this.dataOffset;
+            this.currentParamOffset = new BigNumber(0);
+            this.bindList = {};
+        }
+
+        public bind(dataType: DataType, section: CalldataSection = CalldataSection.DATA) {
+            if (dataType.getId() in this.bindList) {
+                throw `Rebind`;
+            }
+            const memblock = new Memblock(dataType);
+            switch (section) {
+                case CalldataSection.PARAMS:
+                    this.params.push(memblock);
+                    memblock.assignLocation(section, this.currentParamOffset);
+                    this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
+                    break;
+
+                case CalldataSection.DATA:
+                    this.data.push(memblock);
+                    memblock.assignLocation(section, this.currentDataOffset);
+                    this.currentDataOffset = this.currentDataOffset.plus(memblock.getSize());
+                    break;
+
+                default:
+                    throw `Unrecognized calldata section: ${section}`;
+            }
+
+            this.bindList[dataType.getId()] = memblock;
+        }
+
+        public getHexValue(): string {
+            let hexValue = `0x${this.selector}`;
+            _.each(this.params, (memblock: Memblock) => {
+                hexValue += memblock.get();
+            });
+            _.each(this.data, (memblock: Memblock) => {
+                hexValue += memblock.get();
+            });
+
+            return hexValue;
+        }
+    }
 
     export abstract class DataType {
         private dataItem: DataItem;
         private hexValue: string;
+        private memblock: Memblock | undefined;
 
         constructor(dataItem: DataItem) {
             this.dataItem = dataItem;
             this.hexValue = '0x';
+            this.memblock = undefined;
         }
 
         protected assignHexValue(hexValue: string) {
@@ -141,13 +263,25 @@ namespace AbiEncoder {
             return this.dataItem;
         }
 
+        public rbind(memblock: Memblock) {
+            this.memblock = memblock;
+        }
+
+        public bind(calldata: Calldata) {
+            if (this.memblock !== undefined) return; // already binded
+        }
+
+        public getId(): string {
+            return this.dataItem.name;
+        }
+
         public abstract assignValue(value: any): void;
+        public abstract getSignature(): string;
+        public abstract encodeToCalldata(calldata: Calldata): void;
 
         // abstract match(type: string): Bool;
     }
 
-    class Calldata {}
-
     export abstract class StaticDataType extends DataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
@@ -163,7 +297,7 @@ namespace AbiEncoder {
     export class Address extends StaticDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+            expect(Address.matchGrammar(dataItem.type)).to.be.true();
         }
 
         public assignValue(value: string) {
@@ -171,6 +305,14 @@ namespace AbiEncoder {
             this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'address';
         }
@@ -187,6 +329,14 @@ namespace AbiEncoder {
             //this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'bool';
         }
@@ -209,11 +359,19 @@ namespace AbiEncoder {
             }
         }
 
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public assignValue(value: string) {
             //const hexValue = ethUtil.bufferToHex(new Buffer(value));
             //this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
@@ -259,6 +417,14 @@ namespace AbiEncoder {
             this.assignHexValue(encodedValue);
         }
 
+        public getSignature(): string {
+            return `uint${this.width}`;
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
@@ -286,6 +452,14 @@ namespace AbiEncoder {
             //this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
@@ -302,6 +476,14 @@ namespace AbiEncoder {
             //this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'tuple';
         }
@@ -321,6 +503,14 @@ namespace AbiEncoder {
             //this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'bytes';
         }
@@ -345,9 +535,17 @@ namespace AbiEncoder {
             //this.assignHexValue(hexValue);
         }
 
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
+
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
+
+        public getSignature(): string {
+            throw 1;
+        }
     }
 
     export class SolString extends DynamicDataType {
@@ -367,6 +565,12 @@ namespace AbiEncoder {
             this.assignHexValue(encodedValue);
         }
 
+        public getSignature(): string {
+            return 'string';
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {}
+
         public static matchGrammar(type: string): boolean {
             return type === 'string';
         }
@@ -399,6 +603,14 @@ namespace AbiEncoder {
         public getHexValue(): string {
             return this.destDataType.getHexValue();
         }
+
+        public getSignature(): string {
+            return this.destDataType.getSignature();
+        }
+
+        public encodeToCalldata(calldata: Calldata): void {
+            throw 2;
+        }
     }
 
     export class DataTypeFactory {
@@ -437,6 +649,8 @@ namespace AbiEncoder {
     export class Method {
         name: string;
         params: DataType[];
+        signature: string;
+        selector: string;
 
         constructor(abi: MethodAbi) {
             // super();
@@ -446,20 +660,40 @@ namespace AbiEncoder {
             _.each(abi.inputs, (input: DataItem) => {
                 this.params.push(DataTypeFactory.create(input));
             });
+
+            // Compute signature
+            this.signature = `${this.name}(`;
+            _.each(this.params, (param: DataType, i: number) => {
+                this.signature += param.getSignature();
+                if (i < this.params.length - 1) {
+                    this.signature += ',';
+                }
+            });
+            this.signature += ')';
+
+            // Compute selector
+            this.selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(this.signature).slice(0, 4)));
+
+            console.log(`--SIGNATURE--\n${this.signature}\n---------\n`);
+            console.log(`--SELECTOR--\n${this.selector}\n---------\n`);
         }
 
         encode(args: any[]): string {
-            //const calldata = new Calldata(this.name, this.params.length);
-            let params = this.params;
+            const calldata = new Calldata(this.selector, this.params.length);
+
+            // Write params section
+            const params = this.params;
             _.each(params, (param: DataType, i: number) => {
-                console.log('param:\n', param, '\n--end--\n');
-                console.log('arg:\n', args[i], '\n--end\n');
+                // Assign value to param
                 param.assignValue(args[i]);
-                console.log(param.getHexValue());
-                //param.encodeToCalldata(calldata);
+                // Binds top-level parameter to the params section of calldata
+                calldata.bind(param, CalldataSection.PARAMS);
+                // Binds parameter's children to the data section of calldata,
+                // while retaining internal pointers
+                param.bind(calldata);
             });
 
-            return '';
+            return calldata.getHexValue();
 
             //return calldata.getRaw();
         }
@@ -499,10 +733,11 @@ namespace AbiEncoder {
 }
 
 describe.only('ABI Encoder', () => {
-    describe('Just a Greg, Eh', () => {
+    describe.only('Just a Greg, Eh', () => {
         it('Yessir', async () => {
             const method = new AbiEncoder.Method(simpleAbi);
-            method.encode([new BigNumber(5), 'five']);
+            const calldata = method.encode([new BigNumber(5), 'five']);
+            console.log(calldata);
             expect(true).to.be.true();
         });
     });
-- 
cgit v1.2.3


From 7196046e2f38aba4709f61d1a88eb562d6c0a38a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 17:12:13 -0800
Subject: Prints full ABI encoding for subset of types, with off by factor of 2
 for offsets

---
 packages/order-utils/test/abi_encoder_test.ts | 69 +++++++++++++++++++++++----
 1 file changed, 59 insertions(+), 10 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 7e12dfee6..e1d0e8a91 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -153,12 +153,13 @@ namespace AbiEncoder {
 
     class Memblock {
         private dataType: DataType;
-        private location: { calldataSection: CalldataSection; offset: BigNumber };
+        private location: { calldataSection: CalldataSection; sectionOffset: BigNumber; offset: BigNumber };
 
         constructor(dataType: DataType) {
             this.dataType = dataType;
             this.location = {
                 calldataSection: CalldataSection.NONE,
+                sectionOffset: new BigNumber(0),
                 offset: new BigNumber(0),
             };
         }
@@ -167,14 +168,27 @@ namespace AbiEncoder {
             return new BigNumber(ethUtil.toBuffer(this.dataType.getHexValue()).byteLength);
         }
 
-        public assignLocation(calldataSection: CalldataSection, offset: BigNumber) {
+        public assignLocation(calldataSection: CalldataSection, sectionOffset: BigNumber, offset: BigNumber) {
             this.location.calldataSection = calldataSection;
+            this.location.sectionOffset = sectionOffset;
             this.location.offset = offset;
         }
 
         public get(): string {
             return ethUtil.stripHexPrefix(this.dataType.getHexValue());
         }
+
+        public getOffset(): BigNumber {
+            return this.location.offset;
+        }
+
+        public getAbsoluteOffset(): BigNumber {
+            return this.location.sectionOffset.plus(this.location.offset);
+        }
+
+        public getSection(): CalldataSection {
+            return this.location.calldataSection;
+        }
     }
 
     interface BindList {
@@ -204,19 +218,19 @@ namespace AbiEncoder {
 
         public bind(dataType: DataType, section: CalldataSection = CalldataSection.DATA) {
             if (dataType.getId() in this.bindList) {
-                throw `Rebind`;
+                throw `Rebind on ${dataType.getId()}`;
             }
             const memblock = new Memblock(dataType);
             switch (section) {
                 case CalldataSection.PARAMS:
                     this.params.push(memblock);
-                    memblock.assignLocation(section, this.currentParamOffset);
+                    memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
                     this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
                     break;
 
                 case CalldataSection.DATA:
                     this.data.push(memblock);
-                    memblock.assignLocation(section, this.currentDataOffset);
+                    memblock.assignLocation(section, this.dataOffset, this.currentDataOffset);
                     this.currentDataOffset = this.currentDataOffset.plus(memblock.getSize());
                     break;
 
@@ -225,6 +239,7 @@ namespace AbiEncoder {
             }
 
             this.bindList[dataType.getId()] = memblock;
+            dataType.rbind(memblock);
         }
 
         public getHexValue(): string {
@@ -243,12 +258,14 @@ namespace AbiEncoder {
     export abstract class DataType {
         private dataItem: DataItem;
         private hexValue: string;
-        private memblock: Memblock | undefined;
+        protected memblock: Memblock | undefined;
+        protected children: DataType[];
 
         constructor(dataItem: DataItem) {
             this.dataItem = dataItem;
             this.hexValue = '0x';
             this.memblock = undefined;
+            this.children = [];
         }
 
         protected assignHexValue(hexValue: string) {
@@ -268,13 +285,28 @@ namespace AbiEncoder {
         }
 
         public bind(calldata: Calldata) {
-            if (this.memblock !== undefined) return; // already binded
+            if (this.memblock === undefined) {
+                calldata.bind(this);
+            }
+            _.each(this.children, (child: DataType) => {
+                child.bind(calldata);
+            });
         }
 
         public getId(): string {
             return this.dataItem.name;
         }
 
+        public getOffset(): BigNumber {
+            if (this.memblock === undefined) return new BigNumber(0);
+            return this.memblock.getOffset();
+        }
+
+        public getAbsoluteOffset(): BigNumber {
+            if (this.memblock === undefined) return new BigNumber(0);
+            return this.memblock.getAbsoluteOffset();
+        }
+
         public abstract assignValue(value: any): void;
         public abstract getSignature(): string;
         public abstract encodeToCalldata(calldata: Calldata): void;
@@ -401,8 +433,6 @@ namespace AbiEncoder {
         }
 
         public assignValue(value: BigNumber) {
-            console.log(JSON.stringify(value));
-            console.log(JSON.stringify(this.getMaxValue()));
             if (value.greaterThan(this.getMaxValue())) {
                 throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
             } else if (value.lessThan(0)) {
@@ -589,6 +619,7 @@ namespace AbiEncoder {
             const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
             super(dataItem);
             this.destDataType = destDataType;
+            this.children.push(destDataType);
         }
 
         /*
@@ -601,7 +632,23 @@ namespace AbiEncoder {
         }
 
         public getHexValue(): string {
-            return this.destDataType.getHexValue();
+            let offset = new BigNumber(0);
+            if (this.memblock !== undefined) {
+                switch (this.memblock.getSection()) {
+                    case CalldataSection.PARAMS:
+                        offset = this.destDataType.getAbsoluteOffset();
+                        break;
+                    case CalldataSection.DATA:
+                        offset = this.destDataType.getOffset();
+                        break;
+                }
+            }
+
+            const hexBase = 16;
+            const evmWordWidth = 32;
+            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${offset.toString(hexBase)}`), evmWordWidth);
+            const encodedValue = ethUtil.bufferToHex(valueBuf);
+            return encodedValue;
         }
 
         public getSignature(): string {
@@ -693,6 +740,8 @@ namespace AbiEncoder {
                 param.bind(calldata);
             });
 
+            console.log(calldata);
+
             return calldata.getHexValue();
 
             //return calldata.getRaw();
-- 
cgit v1.2.3


From b99252baaedd9bc37ef4e53d02e4085bed7e5142 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 6 Nov 2018 17:18:40 -0800
Subject: ABI encodes some basic types correctly

---
 packages/order-utils/test/abi_encoder_test.ts | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index e1d0e8a91..1a33e4f78 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -211,7 +211,7 @@ namespace AbiEncoder {
             this.data = [];
             const evmWordSize = 32;
             this.dataOffset = new BigNumber(nParams).times(evmWordSize);
-            this.currentDataOffset = this.dataOffset;
+            this.currentDataOffset = new BigNumber(0);
             this.currentParamOffset = new BigNumber(0);
             this.bindList = {};
         }
@@ -243,7 +243,7 @@ namespace AbiEncoder {
         }
 
         public getHexValue(): string {
-            let hexValue = `0x${this.selector}`;
+            let hexValue = `${this.selector}`;
             _.each(this.params, (memblock: Memblock) => {
                 hexValue += memblock.get();
             });
@@ -634,6 +634,8 @@ namespace AbiEncoder {
         public getHexValue(): string {
             let offset = new BigNumber(0);
             if (this.memblock !== undefined) {
+                console.log('Abs Offset = ', JSON.stringify(this.destDataType.getAbsoluteOffset()));
+                console.log('Local Offset = ', JSON.stringify(this.destDataType.getOffset()));
                 switch (this.memblock.getSection()) {
                     case CalldataSection.PARAMS:
                         offset = this.destDataType.getAbsoluteOffset();
-- 
cgit v1.2.3


From fc0e7b1132f8956c470a49b0e964d9ca1812e591 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 10:20:19 -0800
Subject: cleaner bind

---
 packages/order-utils/test/abi_encoder_test.ts | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 1a33e4f78..292e615f3 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -216,7 +216,7 @@ namespace AbiEncoder {
             this.bindList = {};
         }
 
-        public bind(dataType: DataType, section: CalldataSection = CalldataSection.DATA) {
+        public bind(dataType: DataType, section: CalldataSection) {
             if (dataType.getId() in this.bindList) {
                 throw `Rebind on ${dataType.getId()}`;
             }
@@ -284,12 +284,12 @@ namespace AbiEncoder {
             this.memblock = memblock;
         }
 
-        public bind(calldata: Calldata) {
+        public bind(calldata: Calldata, section: CalldataSection) {
             if (this.memblock === undefined) {
-                calldata.bind(this);
+                calldata.bind(this, section);
             }
             _.each(this.children, (child: DataType) => {
-                child.bind(calldata);
+                child.bind(calldata, CalldataSection.DATA);
             });
         }
 
@@ -729,17 +729,10 @@ namespace AbiEncoder {
 
         encode(args: any[]): string {
             const calldata = new Calldata(this.selector, this.params.length);
-
-            // Write params section
             const params = this.params;
             _.each(params, (param: DataType, i: number) => {
-                // Assign value to param
                 param.assignValue(args[i]);
-                // Binds top-level parameter to the params section of calldata
-                calldata.bind(param, CalldataSection.PARAMS);
-                // Binds parameter's children to the data section of calldata,
-                // while retaining internal pointers
-                param.bind(calldata);
+                param.bind(calldata, CalldataSection.PARAMS);
             });
 
             console.log(calldata);
-- 
cgit v1.2.3


From dfa9e435af7477bddb147a8af3700143b27b5dc6 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 10:44:22 -0800
Subject: Implemented Address

---
 packages/order-utils/test/abi_encoder_test.ts | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 292e615f3..7fb091019 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -309,9 +309,6 @@ namespace AbiEncoder {
 
         public abstract assignValue(value: any): void;
         public abstract getSignature(): string;
-        public abstract encodeToCalldata(calldata: Calldata): void;
-
-        // abstract match(type: string): Bool;
     }
 
     export abstract class StaticDataType extends DataType {
@@ -333,16 +330,13 @@ namespace AbiEncoder {
         }
 
         public assignValue(value: string) {
-            const hexValue = ethUtil.bufferToHex(new Buffer(value));
+            const evmWordWidth = 32;
+            const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth));
             this.assignHexValue(hexValue);
         }
 
         public getSignature(): string {
-            throw 1;
-        }
-
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+            return `address`;
         }
 
         public static matchGrammar(type: string): boolean {
@@ -634,8 +628,6 @@ namespace AbiEncoder {
         public getHexValue(): string {
             let offset = new BigNumber(0);
             if (this.memblock !== undefined) {
-                console.log('Abs Offset = ', JSON.stringify(this.destDataType.getAbsoluteOffset()));
-                console.log('Local Offset = ', JSON.stringify(this.destDataType.getOffset()));
                 switch (this.memblock.getSection()) {
                     case CalldataSection.PARAMS:
                         offset = this.destDataType.getAbsoluteOffset();
@@ -786,6 +778,19 @@ describe.only('ABI Encoder', () => {
         });
     });
 
+    describe.only('Address', () => {
+        const testAddressDataItem = { name: 'testAddress', type: 'address' };
+        it('Valid Address', async () => {
+            const addressDataType = new AbiEncoder.Address(testAddressDataItem);
+            addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
+            const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+
+            console.log(addressDataType.getHexValue());
+            console.log(expectedAbiEncodedAddress);
+            expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
+        });
+    });
+
     describe('String', () => {
         const testStringDataItem = { name: 'testString', type: 'string' };
         it('Less than 32 bytes', async () => {
-- 
cgit v1.2.3


From ef5ba0375acbff2f985be08a6bd19b0499628e33 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 10:49:53 -0800
Subject: Implemented bool type

---
 packages/order-utils/test/abi_encoder_test.ts | 35 +++++++++++++++++++--------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 7fb091019..76a6da00e 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -347,20 +347,18 @@ namespace AbiEncoder {
     export class Bool extends StaticDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+            expect(Bool.matchGrammar(dataItem.type)).to.be.true();
         }
 
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
+        public assignValue(value: boolean) {
+            const evmWordWidth = 32;
+            const encodedValue = value === true ? '0x1' : '0x0';
+            const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth));
+            this.assignHexValue(hexValue);
         }
 
         public getSignature(): string {
-            throw 1;
-        }
-
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+            return 'bool';
         }
 
         public static matchGrammar(type: string): boolean {
@@ -778,7 +776,7 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Address', () => {
+    describe('Address', () => {
         const testAddressDataItem = { name: 'testAddress', type: 'address' };
         it('Valid Address', async () => {
             const addressDataType = new AbiEncoder.Address(testAddressDataItem);
@@ -791,6 +789,23 @@ describe.only('ABI Encoder', () => {
         });
     });
 
+    describe.only('Bool', () => {
+        const testBoolDataItem = { name: 'testBool', type: 'bool' };
+        it('True', async () => {
+            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+            boolDataType.assignValue(true);
+            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+        });
+
+        it('False', async () => {
+            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+            boolDataType.assignValue(false);
+            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
+            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+        });
+    });
+
     describe('String', () => {
         const testStringDataItem = { name: 'testString', type: 'string' };
         it('Less than 32 bytes', async () => {
-- 
cgit v1.2.3


From f6cf3de1c4cabc0fcd6a4bb98948096c4924c2bd Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 11:31:49 -0800
Subject: Implemented int

---
 packages/order-utils/test/abi_encoder_test.ts | 105 +++++++++++++++++++++-----
 1 file changed, 87 insertions(+), 18 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 76a6da00e..b557f605d 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -371,29 +371,71 @@ namespace AbiEncoder {
             '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
         );
 
-        static DEFAULT_WIDTH = new BigNumber(1);
-        width: BigNumber = Byte.DEFAULT_WIDTH;
+        static DEFAULT_WIDTH: number = 256;
+        width: number = Int.DEFAULT_WIDTH;
 
         constructor(dataItem: DataItem) {
             super(dataItem);
-            const matches = Byte.matcher.exec(dataItem.type);
+            const matches = Int.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 2) {
-                this.width = new BigNumber(matches[1], 10);
+            if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
+                this.width = parseInt(matches[1]);
+            } else {
+                this.width = 256;
             }
         }
 
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+        public getMaxValue(): BigNumber {
+            return new BigNumber(2).toPower(this.width - 1).sub(1);
         }
 
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
+        public getMinValue(): BigNumber {
+            return new BigNumber(2).toPower(this.width - 1).times(-1);
+        }
+
+        public assignValue(value: BigNumber) {
+            if (value.greaterThan(this.getMaxValue())) {
+                throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+            } else if (value.lessThan(this.getMinValue())) {
+                throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+            }
+
+            const hexBase = 16;
+            const evmWordWidth = 32;
+            let valueBuf: Buffer;
+            if (value.greaterThanOrEqualTo(0)) {
+                valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
+            } else {
+                // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
+                // Step 1/3: Convert value to positive binary string
+                const binBase = 2;
+                const valueBin = value.times(-1).toString(binBase);
+
+                // Step 2/3: Invert binary value
+                const bitsInEvmWord = 256;
+                let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
+                _.each(valueBin, (bit: string) => {
+                    invertedValueBin += bit === '1' ? '0' : '1';
+                });
+                const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+                // Step 3/3: Add 1 to inverted value
+                // The result is the two's-complement represent of the input value.
+                const negativeValue = invertedValue.plus(1);
+
+                // Convert the negated value to a hex string
+                valueBuf = ethUtil.setLengthLeft(
+                    ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
+                    evmWordWidth,
+                );
+            }
+
+            const encodedValue = ethUtil.bufferToHex(valueBuf);
+            this.assignHexValue(encodedValue);
         }
 
         public getSignature(): string {
-            throw 1;
+            return `uint${this.width}`;
         }
 
         public static matchGrammar(type: string): boolean {
@@ -413,7 +455,7 @@ namespace AbiEncoder {
             super(dataItem);
             const matches = UInt.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 2) {
+            if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
                 this.width = parseInt(matches[1]);
             } else {
                 this.width = 256;
@@ -421,7 +463,7 @@ namespace AbiEncoder {
         }
 
         public getMaxValue(): BigNumber {
-            return new BigNumber(2).toPower(this.width - 1);
+            return new BigNumber(2).toPower(this.width).sub(1);
         }
 
         public assignValue(value: BigNumber) {
@@ -443,10 +485,6 @@ namespace AbiEncoder {
             return `uint${this.width}`;
         }
 
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
-        }
-
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
@@ -789,7 +827,7 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Bool', () => {
+    describe('Bool', () => {
         const testBoolDataItem = { name: 'testBool', type: 'bool' };
         it('True', async () => {
             const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
@@ -806,6 +844,37 @@ describe.only('ABI Encoder', () => {
         });
     });
 
+    describe.only('Integer', () => {
+        const testIntDataItem = { name: 'testInt', type: 'int' };
+        it('Positive - Base case', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(1));
+            const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        it('Positive', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(437829473));
+            const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        it('Negative - Base case', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(-1));
+            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        it('Negative', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(-437829473));
+            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+    });
+
     describe('String', () => {
         const testStringDataItem = { name: 'testString', type: 'string' };
         it('Less than 32 bytes', async () => {
-- 
cgit v1.2.3


From e2b115a15c4745494043697130e7d1980cde05f4 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 11:37:07 -0800
Subject: refactored UInt/Int

---
 packages/order-utils/test/abi_encoder_test.ts | 75 ++++++++++++---------------
 1 file changed, 32 insertions(+), 43 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index b557f605d..f9e28015b 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -366,17 +366,14 @@ namespace AbiEncoder {
         }
     }
 
-    export class Int extends StaticDataType {
-        static matcher = RegExp(
-            '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-        );
-
-        static DEFAULT_WIDTH: number = 256;
-        width: number = Int.DEFAULT_WIDTH;
+    abstract class Number extends StaticDataType {
+        static MAX_WIDTH: number = 256;
+        static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
+        width: number = Number.DEFAULT_WIDTH;
 
-        constructor(dataItem: DataItem) {
+        constructor(dataItem: DataItem, matcher: RegExp) {
             super(dataItem);
-            const matches = Int.matcher.exec(dataItem.type);
+            const matches = matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
             if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
                 this.width = parseInt(matches[1]);
@@ -385,14 +382,6 @@ namespace AbiEncoder {
             }
         }
 
-        public getMaxValue(): BigNumber {
-            return new BigNumber(2).toPower(this.width - 1).sub(1);
-        }
-
-        public getMinValue(): BigNumber {
-            return new BigNumber(2).toPower(this.width - 1).times(-1);
-        }
-
         public assignValue(value: BigNumber) {
             if (value.greaterThan(this.getMaxValue())) {
                 throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
@@ -434,8 +423,29 @@ namespace AbiEncoder {
             this.assignHexValue(encodedValue);
         }
 
+        public abstract getMaxValue(): BigNumber;
+        public abstract getMinValue(): BigNumber;
+    }
+
+    export class Int extends Number {
+        static matcher = RegExp(
+            '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+        );
+
+        constructor(dataItem: DataItem) {
+            super(dataItem, Int.matcher);
+        }
+
+        public getMaxValue(): BigNumber {
+            return new BigNumber(2).toPower(this.width - 1).sub(1);
+        }
+
+        public getMinValue(): BigNumber {
+            return new BigNumber(2).toPower(this.width - 1).times(-1);
+        }
+
         public getSignature(): string {
-            return `uint${this.width}`;
+            return `int${this.width}`;
         }
 
         public static matchGrammar(type: string): boolean {
@@ -443,42 +453,21 @@ namespace AbiEncoder {
         }
     }
 
-    export class UInt extends StaticDataType {
+    export class UInt extends Number {
         static matcher = RegExp(
             '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
         );
 
-        static DEFAULT_WIDTH: number = 256;
-        width: number = UInt.DEFAULT_WIDTH;
-
         constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = UInt.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
-                this.width = parseInt(matches[1]);
-            } else {
-                this.width = 256;
-            }
+            super(dataItem, UInt.matcher);
         }
 
         public getMaxValue(): BigNumber {
             return new BigNumber(2).toPower(this.width).sub(1);
         }
 
-        public assignValue(value: BigNumber) {
-            if (value.greaterThan(this.getMaxValue())) {
-                throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
-            } else if (value.lessThan(0)) {
-                throw `tried to assign value of ${value} to an unsigned integer.`;
-            }
-
-            const hexBase = 16;
-            const evmWordWidth = 32;
-            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
-            const encodedValue = ethUtil.bufferToHex(valueBuf);
-
-            this.assignHexValue(encodedValue);
+        public getMinValue(): BigNumber {
+            return new BigNumber(0);
         }
 
         public getSignature(): string {
-- 
cgit v1.2.3


From cef254fa8cacdcba37ec41dec574566b9249b84c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 11:39:48 -0800
Subject: tests for unsigned integer

---
 packages/order-utils/test/abi_encoder_test.ts | 30 ++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index f9e28015b..fb149faa1 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -833,7 +833,7 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Integer', () => {
+    describe('Integer', () => {
         const testIntDataItem = { name: 'testInt', type: 'int' };
         it('Positive - Base case', async () => {
             const intDataType = new AbiEncoder.Int(testIntDataItem);
@@ -862,6 +862,34 @@ describe.only('ABI Encoder', () => {
             const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
             expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
         });
+
+        // TODO: Add bounds tests + tests for different widths
+    });
+
+    describe('Unsigned Integer', () => {
+        const testIntDataItem = { name: 'testUInt', type: 'uint' };
+        it('Lower Bound', async () => {
+            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+            uintDataType.assignValue(new BigNumber(0));
+            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
+            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        });
+
+        it('Base Case', async () => {
+            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+            uintDataType.assignValue(new BigNumber(1));
+            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        });
+
+        it('Random value', async () => {
+            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+            uintDataType.assignValue(new BigNumber(437829473));
+            const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        });
+
+        // TODO: Add bounds tests + tests for different widths
     });
 
     describe('String', () => {
-- 
cgit v1.2.3


From 91a08b9fdd6ec406c6a0e853ff314501347fac94 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 12:54:29 -0800
Subject: Static bytes tests

---
 packages/order-utils/test/abi_encoder_test.ts | 92 +++++++++++++++++++++++----
 1 file changed, 80 insertions(+), 12 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index fb149faa1..6f723036b 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -484,29 +484,43 @@ namespace AbiEncoder {
             '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
         );
 
-        static DEFAULT_WIDTH = new BigNumber(1);
-        width: BigNumber = Byte.DEFAULT_WIDTH;
+        static DEFAULT_WIDTH = 1;
+        width: number = Byte.DEFAULT_WIDTH;
 
         constructor(dataItem: DataItem) {
             super(dataItem);
             const matches = Byte.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 2) {
-                this.width = new BigNumber(matches[1], 10);
+            if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
+                this.width = parseInt(matches[2]);
+            } else {
+                this.width = Byte.DEFAULT_WIDTH;
             }
         }
 
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
-        }
+        public assignValue(value: string | Buffer) {
+            // Convert value into a buffer and do bounds checking
+            const valueBuf = ethUtil.toBuffer(value);
+            if (valueBuf.byteLength > this.width) {
+                throw new Error(
+                    `Tried to assign ${value} (${
+                        valueBuf.byteLength
+                    } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
+                );
+            } else if (value.length % 2 !== 0) {
+                throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+            }
 
-        public getSignature(): string {
-            throw 1;
+            // Store value as hex
+            const evmWordWidth = 32;
+            const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
+            const hexValue = ethUtil.bufferToHex(paddedValue);
+            this.assignHexValue(hexValue);
         }
 
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+        public getSignature(): string {
+            // Note that `byte` reduces to `bytes1`
+            return `bytes${this.width}`;
         }
 
         public static matchGrammar(type: string): boolean {
@@ -892,6 +906,60 @@ describe.only('ABI Encoder', () => {
         // TODO: Add bounds tests + tests for different widths
     });
 
+    describe.only('Static Bytes', () => {
+        it('Byte (padded)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x05');
+            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it.skip('Byte (no padding)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+
+            // @TODO: This does not catch the Error
+            expect(byteDataType.assignValue('0x5')).to.throw();
+        });
+
+        it('Bytes1', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x05');
+            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it('Bytes32 (padded)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
+            const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it('Bytes32 (unpadded)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x1a18bf61');
+            const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it.skip('Bytes32 - Too long', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+
+            // @TODO: This does not catch the Error
+            expect(
+                byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
+            ).to.throw(
+                `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
+            );
+        });
+    });
+
     describe('String', () => {
         const testStringDataItem = { name: 'testString', type: 'string' };
         it('Less than 32 bytes', async () => {
-- 
cgit v1.2.3


From f35cf030308c0f18ad26669bfb3b269a5b96a39e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 13:14:46 -0800
Subject: implemented bytes (dynamic)

---
 packages/order-utils/test/abi_encoder_test.ts | 121 ++++++++++++++++----------
 1 file changed, 77 insertions(+), 44 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 6f723036b..926f7bc81 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -528,37 +528,73 @@ namespace AbiEncoder {
         }
     }
 
-    export class Tuple extends DynamicDataType {
+    export class Bytes extends StaticDataType {
+        static UNDEFINED_LENGTH = new BigNumber(-1);
+        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+
         constructor(dataItem: DataItem) {
             super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+            expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
         }
 
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
+        public assignValue(value: string | Buffer) {
+            if (typeof value === 'string' && !value.startsWith('0x')) {
+                throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
+            }
+            const valueBuf = ethUtil.toBuffer(value);
+            if (value.length % 2 !== 0) {
+                throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+            }
+
+            const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
+            const paddedBytesForValue = wordsForValue * 32;
+            const paddedValueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+            const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
+            const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
+            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
+
+            this.assignHexValue(encodedValue);
         }
 
         public getSignature(): string {
-            throw 1;
+            return 'bytes';
         }
 
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+        public static matchGrammar(type: string): boolean {
+            return type === 'bytes';
+        }
+    }
+
+    export class SolString extends StaticDataType {
+        constructor(dataItem: DataItem) {
+            super(dataItem);
+            expect(SolString.matchGrammar(dataItem.type)).to.be.true();
+        }
+
+        public assignValue(value: string) {
+            const wordsForValue = Math.ceil(value.length / 32);
+            const paddedBytesForValue = wordsForValue * 32;
+            const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+            const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+            const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
+
+            this.assignHexValue(encodedValue);
+        }
+
+        public getSignature(): string {
+            return 'string';
         }
 
         public static matchGrammar(type: string): boolean {
-            return type === 'tuple';
+            return type === 'string';
         }
     }
 
-    export class Bytes extends StaticDataType {
-        static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = SolArray.UNDEFINED_LENGTH;
-
+    export class Tuple extends DynamicDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
-            expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
         }
 
         public assignValue(value: string) {
@@ -575,7 +611,7 @@ namespace AbiEncoder {
         }
 
         public static matchGrammar(type: string): boolean {
-            return type === 'bytes';
+            return type === 'tuple';
         }
     }
 
@@ -611,34 +647,6 @@ namespace AbiEncoder {
         }
     }
 
-    export class SolString extends DynamicDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(SolString.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            const wordsForValue = Math.ceil(value.length / 32);
-            const paddedBytesForValue = wordsForValue * 32;
-            const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-            const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
-            const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
-
-            this.assignHexValue(encodedValue);
-        }
-
-        public getSignature(): string {
-            return 'string';
-        }
-
-        public encodeToCalldata(calldata: Calldata): void {}
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'string';
-        }
-    }
-
     /* TODO
     class Fixed extends StaticDataType {}
 
@@ -906,7 +914,7 @@ describe.only('ABI Encoder', () => {
         // TODO: Add bounds tests + tests for different widths
     });
 
-    describe.only('Static Bytes', () => {
+    describe('Static Bytes', () => {
         it('Byte (padded)', async () => {
             const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
             const byteDataType = new AbiEncoder.Byte(testByteDataItem);
@@ -960,6 +968,31 @@ describe.only('ABI Encoder', () => {
         });
     });
 
+    describe.only('Bytes (Dynamic)', () => {
+        const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
+        it('Less than 32 bytes', async () => {
+            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+            bytesDataType.assignValue('0x010203');
+            const expectedAbiEncodedBytes =
+                '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
+
+            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+        });
+
+        it('Greater than 32 bytes', async () => {
+            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+            const testValue = '0x' + '61'.repeat(40);
+            bytesDataType.assignValue(testValue);
+            const expectedAbiEncodedBytes =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+        });
+
+        // @TODO: Add test for throw on half-byte
+        // @TODO: Test with no 0x prefix
+        // @TODO: Test with Buffer as input
+    });
+
     describe('String', () => {
         const testStringDataItem = { name: 'testString', type: 'string' };
         it('Less than 32 bytes', async () => {
-- 
cgit v1.2.3


From 5053c19599e96b9886e6b36173350162b92405a3 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 13:44:27 -0800
Subject: constructor for an Array + a test -- appears to work

---
 packages/order-utils/test/abi_encoder_test.ts | 87 ++++++++++++++++++---------
 1 file changed, 58 insertions(+), 29 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 926f7bc81..bed75b935 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -528,7 +528,7 @@ namespace AbiEncoder {
         }
     }
 
-    export class Bytes extends StaticDataType {
+    export class Bytes extends DynamicDataType {
         static UNDEFINED_LENGTH = new BigNumber(-1);
         length: BigNumber = SolArray.UNDEFINED_LENGTH;
 
@@ -565,7 +565,7 @@ namespace AbiEncoder {
         }
     }
 
-    export class SolString extends StaticDataType {
+    export class SolString extends DynamicDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
             expect(SolString.matchGrammar(dataItem.type)).to.be.true();
@@ -591,42 +591,63 @@ namespace AbiEncoder {
         }
     }
 
-    export class Tuple extends DynamicDataType {
+    export class SolArray extends DynamicDataType {
+        static matcher = RegExp('^(.+)\\[([0-9]d*)\\]$');
+        static UNDEFINED_LENGTH = new BigNumber(-1);
+        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+        type: string = '[undefined]';
+
         constructor(dataItem: DataItem) {
             super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+            const matches = SolArray.matcher.exec(dataItem.type);
+            expect(matches).to.be.not.null();
+            if (matches === null || matches.length !== 3) {
+                throw new Error(`Could not parse array: ${dataItem.type}`);
+            } else if (matches[1] === undefined) {
+                throw new Error(`Could not parse array type: ${dataItem.type}`);
+            } else if (matches[2] === undefined) {
+                // Parse out array type and length
+                this.type = matches[1];
+                this.length = new BigNumber(SolArray.UNDEFINED_LENGTH);
+                return;
+            }
+
+            // Parse out array type and length
+            this.type = matches[1];
+            this.length = new BigNumber(matches[2], 10);
+            if (this.length.lessThan(0)) {
+                throw new Error(`Bad array length: ${JSON.stringify(this.length)}`);
+            }
+
+            // Construct children
+            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+                const childDataItem = {
+                    type: this.type,
+                    name: `${this.getDataItem().name}[${idx.toString(10)}]`,
+                } as DataItem;
+                const child = DataTypeFactory.create(childDataItem);
+                this.children.push(child);
+            }
         }
 
-        public assignValue(value: string) {
+        public assignValue(value: any[]) {
             //const hexValue = ethUtil.bufferToHex(new Buffer(value));
             //this.assignHexValue(hexValue);
         }
 
-        public getSignature(): string {
-            throw 1;
-        }
-
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+        public static matchGrammar(type: string): boolean {
+            return this.matcher.test(type);
         }
 
-        public static matchGrammar(type: string): boolean {
-            return type === 'tuple';
+        public getSignature(): string {
+            return `${this.type}[${this.length}]`;
         }
     }
 
-    export class SolArray extends DynamicDataType {
-        static matcher = RegExp('^.+\\[([0-9]d*)\\]$');
-        static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = SolArray.UNDEFINED_LENGTH;
-
+    export class Tuple extends DynamicDataType {
         constructor(dataItem: DataItem) {
             super(dataItem);
-            const matches = SolArray.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 1) {
-                this.length = new BigNumber(matches[1], 10);
-            }
+            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
         }
 
         public assignValue(value: string) {
@@ -634,16 +655,16 @@ namespace AbiEncoder {
             //this.assignHexValue(hexValue);
         }
 
+        public getSignature(): string {
+            throw 1;
+        }
+
         public encodeToCalldata(calldata: Calldata): void {
             throw 2;
         }
 
         public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-
-        public getSignature(): string {
-            throw 1;
+            return type === 'tuple';
         }
     }
 
@@ -816,7 +837,15 @@ namespace AbiEncoder {
 }
 
 describe.only('ABI Encoder', () => {
-    describe.only('Just a Greg, Eh', () => {
+    describe.only('Array', () => {
+        it('sample', async () => {
+            const testDataItem = { name: 'testArray', type: 'string[2]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            console.log(JSON.stringify(dataType, null, 4));
+        });
+    });
+
+    describe('Just a Greg, Eh', () => {
         it('Yessir', async () => {
             const method = new AbiEncoder.Method(simpleAbi);
             const calldata = method.encode([new BigNumber(5), 'five']);
-- 
cgit v1.2.3


From 7de7fe782398eded47598046699fdc0915597e33 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 14:18:05 -0800
Subject: Array of basic types works

---
 packages/order-utils/test/abi_encoder_test.ts | 53 ++++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 5 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index bed75b935..a455e6a00 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -612,14 +612,16 @@ namespace AbiEncoder {
                 return;
             }
 
-            // Parse out array type and length
+            // Parse out array type/length and construct children
             this.type = matches[1];
             this.length = new BigNumber(matches[2], 10);
             if (this.length.lessThan(0)) {
                 throw new Error(`Bad array length: ${JSON.stringify(this.length)}`);
             }
+            this.constructChildren();
+        }
 
-            // Construct children
+        private constructChildren() {
             for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
                 const childDataItem = {
                     type: this.type,
@@ -631,8 +633,43 @@ namespace AbiEncoder {
         }
 
         public assignValue(value: any[]) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
+            // Sanity check length
+            const valueLength = new BigNumber(value.length);
+            if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
+                throw new Error(
+                    `Expected array of length ${JSON.stringify(this.length)}, but got array of length ${JSON.stringify(
+                        valueLength,
+                    )}`,
+                );
+            }
+
+            // Assign length if not already set
+            if (this.length === SolArray.UNDEFINED_LENGTH) {
+                this.length = valueLength;
+                this.constructChildren();
+            }
+
+            // Assign values to children
+            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+                const idxNumber = idx.toNumber();
+                this.children[idxNumber].assignValue(value[idxNumber]);
+            }
+        }
+
+        public getHexValue(): string {
+            const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
+            const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
+            let valueBuf = lengthBuf;
+            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+                const idxNumber = idx.toNumber();
+                const childValueHex = this.children[idxNumber].getHexValue();
+                const childValueBuf = ethUtil.toBuffer(childValueHex);
+                valueBuf = Buffer.concat([valueBuf, childValueBuf]);
+            }
+
+            // Convert value buffer to hex
+            const valueHex = ethUtil.bufferToHex(valueBuf);
+            return valueHex;
         }
 
         public static matchGrammar(type: string): boolean {
@@ -839,9 +876,15 @@ namespace AbiEncoder {
 describe.only('ABI Encoder', () => {
     describe.only('Array', () => {
         it('sample', async () => {
-            const testDataItem = { name: 'testArray', type: 'string[2]' };
+            const testDataItem = { name: 'testArray', type: 'int[2]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
             console.log(JSON.stringify(dataType, null, 4));
+            console.log('*'.repeat(60));
+            dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+            console.log(JSON.stringify(dataType, null, 4));
+            const hexValue = dataType.getHexValue();
+            console.log('*'.repeat(60));
+            console.log(hexValue);
         });
     });
 
-- 
cgit v1.2.3


From 39fa26b2f3b4c34c7ff4aa87d6b99ff1af8a4c36 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 14:23:50 -0800
Subject: arrays with dynamic size

---
 packages/order-utils/test/abi_encoder_test.ts | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index a455e6a00..0d7f68780 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -592,7 +592,7 @@ namespace AbiEncoder {
     }
 
     export class SolArray extends DynamicDataType {
-        static matcher = RegExp('^(.+)\\[([0-9]d*)\\]$');
+        static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
         static UNDEFINED_LENGTH = new BigNumber(-1);
         length: BigNumber = SolArray.UNDEFINED_LENGTH;
         type: string = '[undefined]';
@@ -601,14 +601,19 @@ namespace AbiEncoder {
             super(dataItem);
             const matches = SolArray.matcher.exec(dataItem.type);
             expect(matches).to.be.not.null();
+            console.log(JSON.stringify(matches));
             if (matches === null || matches.length !== 3) {
                 throw new Error(`Could not parse array: ${dataItem.type}`);
             } else if (matches[1] === undefined) {
                 throw new Error(`Could not parse array type: ${dataItem.type}`);
             } else if (matches[2] === undefined) {
-                // Parse out array type and length
+                throw new Error(`Could not parse array length: ${dataItem.type}`);
+            }
+
+            // Check if length is undefined
+            if (matches[2] === '') {
                 this.type = matches[1];
-                this.length = new BigNumber(SolArray.UNDEFINED_LENGTH);
+                this.length = SolArray.UNDEFINED_LENGTH;
                 return;
             }
 
@@ -886,6 +891,18 @@ describe.only('ABI Encoder', () => {
             console.log('*'.repeat(60));
             console.log(hexValue);
         });
+
+        it.only('sample undefined size', async () => {
+            const testDataItem = { name: 'testArray', type: 'int[]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            console.log(JSON.stringify(dataType, null, 4));
+            console.log('*'.repeat(60));
+            dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+            console.log(JSON.stringify(dataType, null, 4));
+            const hexValue = dataType.getHexValue();
+            console.log('*'.repeat(60));
+            console.log(hexValue);
+        });
     });
 
     describe('Just a Greg, Eh', () => {
-- 
cgit v1.2.3


From 9f35096fa98a17be0e6ed98dcc4c363a5c4e96f7 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 14:37:05 -0800
Subject: corrected selector for Array

---
 packages/order-utils/test/abi_encoder_test.ts | 58 ++++++++++++++++++++++++---
 1 file changed, 52 insertions(+), 6 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 0d7f68780..8e24c8299 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -32,6 +32,21 @@ const simpleAbi = {
     type: 'function',
 } as MethodAbi;
 
+const stringAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 const fillOrderAbi = {
     constant: false,
     inputs: [
@@ -145,7 +160,7 @@ namespace AbiEncoder {
         }
     }
 
-    enum CalldataSection {
+    export enum CalldataSection {
         NONE,
         PARAMS,
         DATA,
@@ -195,7 +210,7 @@ namespace AbiEncoder {
         [key: string]: Memblock;
     }
 
-    class Calldata {
+    export class Calldata {
         private selector: string;
         private params: Memblock[];
         private data: Memblock[];
@@ -530,7 +545,7 @@ namespace AbiEncoder {
 
     export class Bytes extends DynamicDataType {
         static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = SolArray.UNDEFINED_LENGTH;
+        length: BigNumber = Bytes.UNDEFINED_LENGTH;
 
         constructor(dataItem: DataItem) {
             super(dataItem);
@@ -682,6 +697,9 @@ namespace AbiEncoder {
         }
 
         public getSignature(): string {
+            if (this.length.equals(SolArray.UNDEFINED_LENGTH)) {
+                return `${this.type}[]`;
+            }
             return `${this.type}[${this.length}]`;
         }
     }
@@ -879,7 +897,7 @@ namespace AbiEncoder {
 }
 
 describe.only('ABI Encoder', () => {
-    describe.only('Array', () => {
+    describe('Array', () => {
         it('sample', async () => {
             const testDataItem = { name: 'testArray', type: 'int[2]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
@@ -892,7 +910,7 @@ describe.only('ABI Encoder', () => {
             console.log(hexValue);
         });
 
-        it.only('sample undefined size', async () => {
+        it('sample undefined size', async () => {
             const testDataItem = { name: 'testArray', type: 'int[]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
             console.log(JSON.stringify(dataType, null, 4));
@@ -903,15 +921,43 @@ describe.only('ABI Encoder', () => {
             console.log('*'.repeat(60));
             console.log(hexValue);
         });
+
+        it('sample dynamic types', async () => {
+            const testDataItem = { name: 'testArray', type: 'string[]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            console.log(JSON.stringify(dataType, null, 4));
+            console.log('*'.repeat(60));
+            dataType.assignValue(['five', 'six', 'seven']);
+            console.log(JSON.stringify(dataType, null, 4));
+            const hexValue = dataType.getHexValue();
+            console.log('*'.repeat(60));
+            console.log(hexValue);
+            const calldata = new AbiEncoder.Calldata('0x01020304', 1);
+            dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
+            console.log('*'.repeat(60));
+            console.log(calldata.getHexValue());
+        });
     });
 
-    describe('Just a Greg, Eh', () => {
+    describe.only('Just a Greg, Eh', () => {
         it('Yessir', async () => {
             const method = new AbiEncoder.Method(simpleAbi);
             const calldata = method.encode([new BigNumber(5), 'five']);
             console.log(calldata);
             expect(true).to.be.true();
         });
+
+        it.only('Yessir', async () => {
+            const method = new AbiEncoder.Method(stringAbi);
+            const calldata = method.encode([['five', 'six', 'seven']]);
+            console.log(method.signature);
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
     });
 
     describe('Address', () => {
-- 
cgit v1.2.3


From 2b4febe337ec188ef0f105f817c124d9a583d669 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 15:22:09 -0800
Subject: switched from depth-first to breadth-first param binding

---
 packages/order-utils/test/abi_encoder_test.ts | 87 ++++++++++++++++++---------
 1 file changed, 58 insertions(+), 29 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 8e24c8299..cd721202e 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -240,12 +240,20 @@ namespace AbiEncoder {
                 case CalldataSection.PARAMS:
                     this.params.push(memblock);
                     memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
+
+                    console.log(`Binding ${dataType.getDataItem().name} to PARAMS at ${this.currentParamOffset}`);
                     this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
                     break;
 
                 case CalldataSection.DATA:
                     this.data.push(memblock);
                     memblock.assignLocation(section, this.dataOffset, this.currentDataOffset);
+
+                    console.log(
+                        `Binding ${dataType.getDataItem().name} to DATA at ${memblock
+                            .getAbsoluteOffset()
+                            .toString(16)}`,
+                    );
                     this.currentDataOffset = this.currentDataOffset.plus(memblock.getSize());
                     break;
 
@@ -300,12 +308,7 @@ namespace AbiEncoder {
         }
 
         public bind(calldata: Calldata, section: CalldataSection) {
-            if (this.memblock === undefined) {
-                calldata.bind(this, section);
-            }
-            _.each(this.children, (child: DataType) => {
-                child.bind(calldata, CalldataSection.DATA);
-            });
+            calldata.bind(this, section);
         }
 
         public getId(): string {
@@ -322,6 +325,10 @@ namespace AbiEncoder {
             return this.memblock.getAbsoluteOffset();
         }
 
+        public getChildren(): DataType[] {
+            return this.children;
+        }
+
         public abstract assignValue(value: any): void;
         public abstract getSignature(): string;
     }
@@ -680,12 +687,12 @@ namespace AbiEncoder {
             const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
             const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
             let valueBuf = lengthBuf;
-            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+            /*for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
                 const idxNumber = idx.toNumber();
                 const childValueHex = this.children[idxNumber].getHexValue();
                 const childValueBuf = ethUtil.toBuffer(childValueHex);
                 valueBuf = Buffer.concat([valueBuf, childValueBuf]);
-            }
+            }*/
 
             // Convert value buffer to hex
             const valueHex = ethUtil.bufferToHex(valueBuf);
@@ -815,6 +822,16 @@ namespace AbiEncoder {
         }
     }
 
+    class Queue<T> {
+        private store: T[] = [];
+        push(val: T) {
+            this.store.push(val);
+        }
+        pop(): T | undefined {
+            return this.store.shift();
+        }
+    }
+
     export class Method {
         name: string;
         params: DataType[];
@@ -850,11 +867,23 @@ namespace AbiEncoder {
         encode(args: any[]): string {
             const calldata = new Calldata(this.selector, this.params.length);
             const params = this.params;
+            const paramQueue = new Queue<DataType>();
             _.each(params, (param: DataType, i: number) => {
                 param.assignValue(args[i]);
                 param.bind(calldata, CalldataSection.PARAMS);
+                _.each(param.getChildren(), (child: DataType) => {
+                    paramQueue.push(child);
+                });
             });
 
+            let param: DataType | undefined = undefined;
+            while ((param = paramQueue.pop()) !== undefined) {
+                param.bind(calldata, CalldataSection.DATA);
+                _.each(param.getChildren(), (child: DataType) => {
+                    paramQueue.push(child);
+                });
+            }
+
             console.log(calldata);
 
             return calldata.getHexValue();
@@ -897,6 +926,27 @@ namespace AbiEncoder {
 }
 
 describe.only('ABI Encoder', () => {
+    describe.only('Just a Greg, Eh', () => {
+        it('Yessir', async () => {
+            const method = new AbiEncoder.Method(simpleAbi);
+            const calldata = method.encode([new BigNumber(5), 'five']);
+            console.log(calldata);
+            expect(true).to.be.true();
+        });
+
+        it.only('Yessir', async () => {
+            const method = new AbiEncoder.Method(stringAbi);
+            const calldata = method.encode([['five', 'six', 'seven']]);
+            console.log(method.signature);
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+    });
+
     describe('Array', () => {
         it('sample', async () => {
             const testDataItem = { name: 'testArray', type: 'int[2]' };
@@ -939,27 +989,6 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Just a Greg, Eh', () => {
-        it('Yessir', async () => {
-            const method = new AbiEncoder.Method(simpleAbi);
-            const calldata = method.encode([new BigNumber(5), 'five']);
-            console.log(calldata);
-            expect(true).to.be.true();
-        });
-
-        it.only('Yessir', async () => {
-            const method = new AbiEncoder.Method(stringAbi);
-            const calldata = method.encode([['five', 'six', 'seven']]);
-            console.log(method.signature);
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
-    });
-
     describe('Address', () => {
         const testAddressDataItem = { name: 'testAddress', type: 'address' };
         it('Valid Address', async () => {
-- 
cgit v1.2.3


From 02f37fa2d9788b81c9f22abb04d12078bce1719e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 16:20:07 -0800
Subject: Works for encoding arrays

---
 packages/order-utils/test/abi_encoder_test.ts | 58 +++++++++++++++++----------
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index cd721202e..23af071b7 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -325,6 +325,11 @@ namespace AbiEncoder {
             return this.memblock.getAbsoluteOffset();
         }
 
+        public getSize(): BigNumber {
+            if (this.memblock === undefined) return new BigNumber(0);
+            return this.memblock.getSize();
+        }
+
         public getChildren(): DataType[] {
             return this.children;
         }
@@ -654,7 +659,7 @@ namespace AbiEncoder {
                     type: this.type,
                     name: `${this.getDataItem().name}[${idx.toString(10)}]`,
                 } as DataItem;
-                const child = DataTypeFactory.create(childDataItem);
+                const child = DataTypeFactory.create(childDataItem, this);
                 this.children.push(child);
             }
         }
@@ -742,12 +747,14 @@ namespace AbiEncoder {
 
     export class Pointer extends StaticDataType {
         destDataType: DynamicDataType;
+        parentDataType: DataType;
 
-        constructor(destDataType: DynamicDataType) {
+        constructor(destDataType: DynamicDataType, parentDataType: DataType) {
             const destDataItem = destDataType.getDataItem();
             const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
             super(dataItem);
             this.destDataType = destDataType;
+            this.parentDataType = parentDataType;
             this.children.push(destDataType);
         }
 
@@ -761,18 +768,16 @@ namespace AbiEncoder {
         }
 
         public getHexValue(): string {
-            let offset = new BigNumber(0);
-            if (this.memblock !== undefined) {
-                switch (this.memblock.getSection()) {
-                    case CalldataSection.PARAMS:
-                        offset = this.destDataType.getAbsoluteOffset();
-                        break;
-                    case CalldataSection.DATA:
-                        offset = this.destDataType.getOffset();
-                        break;
-                }
-            }
+            console.log(
+                '*'.repeat(40),
+                this.destDataType.getAbsoluteOffset().toString(16),
+                '^'.repeat(150),
+                this.parentDataType.getAbsoluteOffset().toString(16),
+            );
 
+            let offset = this.destDataType
+                .getAbsoluteOffset()
+                .minus(this.parentDataType.getAbsoluteOffset().plus(this.parentDataType.getSize()));
             const hexBase = 16;
             const evmWordWidth = 32;
             const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${offset.toString(hexBase)}`), evmWordWidth);
@@ -809,12 +814,12 @@ namespace AbiEncoder {
             throw new Error(`Unrecognized data type: '${dataItem.type}'`);
         }
 
-        public static create(dataItem: DataItem): DataType {
+        public static create(dataItem: DataItem, parentDataType: DataType): DataType {
             const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
             if (dataType instanceof StaticDataType) {
                 return dataType;
             } else if (dataType instanceof DynamicDataType) {
-                const pointer = new Pointer(dataType);
+                const pointer = new Pointer(dataType, parentDataType);
                 return pointer;
             }
 
@@ -832,19 +837,19 @@ namespace AbiEncoder {
         }
     }
 
-    export class Method {
+    export class Method extends DataType {
         name: string;
         params: DataType[];
-        signature: string;
+        private signature: string;
         selector: string;
 
         constructor(abi: MethodAbi) {
-            // super();
+            super({ type: 'method', name: abi.name });
             this.name = abi.name;
             this.params = [];
 
             _.each(abi.inputs, (input: DataItem) => {
-                this.params.push(DataTypeFactory.create(input));
+                this.params.push(DataTypeFactory.create(input, this));
             });
 
             // Compute signature
@@ -864,7 +869,11 @@ namespace AbiEncoder {
             console.log(`--SELECTOR--\n${this.selector}\n---------\n`);
         }
 
-        encode(args: any[]): string {
+        public getSignature(): string {
+            return this.signature;
+        }
+
+        public assignValue(args: any[]) {
             const calldata = new Calldata(this.selector, this.params.length);
             const params = this.params;
             const paramQueue = new Queue<DataType>();
@@ -886,11 +895,16 @@ namespace AbiEncoder {
 
             console.log(calldata);
 
-            return calldata.getHexValue();
+            this.assignHexValue(calldata.getHexValue());
 
             //return calldata.getRaw();
         }
 
+        public encode(args: any[]): string {
+            this.assignValue(args);
+            return this.getHexValue();
+        }
+
         /*
         encodeOptimized(args: any[]): string {
             const calldata = new Memory();
@@ -937,7 +951,7 @@ describe.only('ABI Encoder', () => {
         it.only('Yessir', async () => {
             const method = new AbiEncoder.Method(stringAbi);
             const calldata = method.encode([['five', 'six', 'seven']]);
-            console.log(method.signature);
+            console.log(method.getSignature());
             console.log(method.selector);
 
             console.log(calldata);
-- 
cgit v1.2.3


From af27dd6fe48d4216fad470b5e4ce7b39ef0b0888 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 17:03:09 -0800
Subject: tests for tuple

---
 packages/order-utils/test/abi_encoder_test.ts | 161 ++++++++++++++++++++++++--
 1 file changed, 153 insertions(+), 8 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 23af071b7..499dfe5ee 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -47,6 +47,31 @@ const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
+const tupleAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 const fillOrderAbi = {
     constant: false,
     inputs: [
@@ -717,22 +742,90 @@ namespace AbiEncoder {
     }
 
     export class Tuple extends DynamicDataType {
+        private length: BigNumber;
+        private childMap: { [key: string]: number };
+
         constructor(dataItem: DataItem) {
             super(dataItem);
             expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+            this.length = new BigNumber(0);
+            this.childMap = {};
+            if (dataItem.components !== undefined) {
+                this.constructChildren(dataItem.components);
+                this.length = new BigNumber(dataItem.components.length);
+            }
         }
 
-        public assignValue(value: string) {
-            //const hexValue = ethUtil.bufferToHex(new Buffer(value));
-            //this.assignHexValue(hexValue);
+        private constructChildren(dataItems: DataItem[]) {
+            _.each(dataItems, (dataItem: DataItem) => {
+                const childDataItem = {
+                    type: dataItem.type,
+                    name: `${this.getDataItem().name}.${dataItem.name}`,
+                } as DataItem;
+                const child = DataTypeFactory.create(childDataItem, this);
+                this.childMap[dataItem.name] = this.children.length;
+                this.children.push(child);
+            });
         }
 
-        public getSignature(): string {
-            throw 1;
+        private assignValueFromArray(value: any[]) {
+            // Sanity check length
+            const valueLength = new BigNumber(value.length);
+            if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
+                throw new Error(
+                    `Expected array of length ${JSON.stringify(this.length)}, but got array of length ${JSON.stringify(
+                        valueLength,
+                    )}`,
+                );
+            }
+
+            // Assign values to children
+            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+                const idxNumber = idx.toNumber();
+                this.children[idxNumber].assignValue(value[idxNumber]);
+            }
         }
 
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
+        private assignValueFromObject(obj: object) {
+            let childMap = _.cloneDeep(this.childMap);
+            _.forOwn(obj, (value: any, key: string) => {
+                if (key in childMap === false) {
+                    throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
+                }
+                this.children[this.childMap[key]].assignValue(value);
+                delete childMap[key];
+            });
+
+            if (Object.keys(childMap).length !== 0) {
+                throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+            }
+        }
+
+        public assignValue(value: any[] | object) {
+            if (value instanceof Array) {
+                this.assignValueFromArray(value);
+            } else if (typeof value === 'object') {
+                this.assignValueFromObject(value);
+            } else {
+                throw new Error(`Unexpected type for ${value}`);
+            }
+        }
+
+        public getHexValue(): string {
+            return '0x';
+        }
+
+        public getSignature(): string {
+            // Compute signature
+            let signature = `(`;
+            _.each(this.children, (child: DataType, i: number) => {
+                signature += child.getSignature();
+                if (i < this.children.length - 1) {
+                    signature += ',';
+                }
+            });
+            signature += ')';
+            return signature;
         }
 
         public static matchGrammar(type: string): boolean {
@@ -948,7 +1041,7 @@ describe.only('ABI Encoder', () => {
             expect(true).to.be.true();
         });
 
-        it.only('Yessir', async () => {
+        it('Array ABI', async () => {
             const method = new AbiEncoder.Method(stringAbi);
             const calldata = method.encode([['five', 'six', 'seven']]);
             console.log(method.getSignature());
@@ -959,6 +1052,58 @@ describe.only('ABI Encoder', () => {
                 '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
         });
+
+        it('Object ABI (Array input)', async () => {
+            const method = new AbiEncoder.Method(tupleAbi);
+            const calldata = method.encode([[new BigNumber(5), 'five']]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Object ABI (Object input)', async () => {
+            const method = new AbiEncoder.Method(tupleAbi);
+            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.skip('Object ABI (Object input - Missing Key)', async () => {
+            const method = new AbiEncoder.Method(tupleAbi);
+            const calldata = method.encode([{ someUint: new BigNumber(5) }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+
+            // @TODO: Figure out how to catch throw
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.skip('Object ABI (Object input - Too Many Keys)', async () => {
+            const method = new AbiEncoder.Method(tupleAbi);
+            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five', unwantedKey: 14 }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+
+            // @TODO: Figure out how to catch throw
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
     });
 
     describe('Array', () => {
-- 
cgit v1.2.3


From 993c5f4b4a084a210fa158e643027e63fb9443f8 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 7 Nov 2018 20:38:55 -0800
Subject: Another passing simple Abi 2

---
 packages/order-utils/test/abi_encoder_test.ts | 342 +++++++++++++++++++++++++-
 1 file changed, 335 insertions(+), 7 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 499dfe5ee..95b6630ee 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -72,6 +72,165 @@ const tupleAbi = {
     type: 'function',
 } as MethodAbi;
 
+const crazyAbi = {
+    constant: false,
+    inputs: [
+        /*{
+            name: 'someUInt256',
+            type: 'uint256',
+        },
+        {
+            name: 'someInt256',
+            type: 'int256',
+        },
+        {
+            name: 'someInt32',
+            type: 'int32',
+        },*/
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+        /*{
+            name: 'someAddress',
+            type: 'address',
+        },
+        {
+            name: 'someBool',
+            type: 'bool',
+        },*/
+
+        /*
+
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        },
+        {
+            name: 'someStaticArrayWithDynamicMembers',
+            type: 'string[2]',
+        },
+        {
+            name: 'someDynamicArrayWithDynamicMembers',
+            type: 'bytes[]',
+        },
+        {
+            name: 'some2DArray',
+            type: 'string[][]',
+        },
+        {
+            name: 'someTuple',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+        },
+        {
+            name: 'someTupleWithDynamicTypes',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                //{
+              //      name: 'someStrArray',
+               //     type: 'string[]',
+               /// },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        } /*,
+        {
+            name: 'someArrayOfTuplesWithDynamicTypes',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                {
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        },*/
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+const simpleAbi2 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 const fillOrderAbi = {
     constant: false,
     inputs: [
@@ -734,10 +893,24 @@ namespace AbiEncoder {
         }
 
         public getSignature(): string {
+            let type = this.type;
+            if (this.type === 'tuple') {
+                let tupleDataItem = {
+                    type: 'tuple',
+                    name: 'N/A',
+                } as DataItem;
+                const tupleComponents = this.getDataItem().components;
+                if (tupleComponents !== undefined) {
+                    tupleDataItem.components = tupleComponents;
+                }
+                const tuple = new Tuple(tupleDataItem);
+                type = tuple.getSignature();
+            }
+
             if (this.length.equals(SolArray.UNDEFINED_LENGTH)) {
-                return `${this.type}[]`;
+                return `${type}[]`;
             }
-            return `${this.type}[${this.length}]`;
+            return `${type}[${this.length}]`;
         }
     }
 
@@ -753,6 +926,8 @@ namespace AbiEncoder {
             if (dataItem.components !== undefined) {
                 this.constructChildren(dataItem.components);
                 this.length = new BigNumber(dataItem.components.length);
+            } else {
+                throw new Error('Components undefined');
             }
         }
 
@@ -773,9 +948,9 @@ namespace AbiEncoder {
             const valueLength = new BigNumber(value.length);
             if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
                 throw new Error(
-                    `Expected array of length ${JSON.stringify(this.length)}, but got array of length ${JSON.stringify(
-                        valueLength,
-                    )}`,
+                    `Expected array of ${JSON.stringify(
+                        this.length,
+                    )} elements, but got array of length ${JSON.stringify(valueLength)}`,
                 );
             }
 
@@ -971,7 +1146,12 @@ namespace AbiEncoder {
             const params = this.params;
             const paramQueue = new Queue<DataType>();
             _.each(params, (param: DataType, i: number) => {
-                param.assignValue(args[i]);
+                try {
+                    param.assignValue(args[i]);
+                } catch (e) {
+                    console.log('Failed to assign to ', param.getDataItem().name);
+                    throw e;
+                }
                 param.bind(calldata, CalldataSection.PARAMS);
                 _.each(param.getChildren(), (child: DataType) => {
                     paramQueue.push(child);
@@ -1034,6 +1214,154 @@ namespace AbiEncoder {
 
 describe.only('ABI Encoder', () => {
     describe.only('Just a Greg, Eh', () => {
+        it.skip('Crazy ABI', async () => {
+            const method = new AbiEncoder.Method(crazyAbi);
+            console.log(method.getSignature());
+
+            /*
+            (uint256 b,int256 c,int32 d,
+                bytes1 e,bytes32 f,
+                bytes g,string h,address i,bool j,uint8[3] k,string[2] l,bytes[] m, string[][] n, O o,P p, P[]) 
+
+                struct P {
+                    uint256 a;
+                    string b;
+                    string[] c;
+                    bytes d;
+                    address e;
+                }*/
+
+            const args = [
+                /*new BigNumber(437829473), // b
+                new BigNumber(-437829473), // c
+                new BigNumber(-14), // d*/
+                '0xaf', // e (bytes1)
+                '0x0001020304050607080911121314151617181920212223242526272829303132', // f (bytes32)
+                '0x616161616161616161616161616161616161616161616161616161616161616161616161616161611114f324567838475647382938475677448899338457668899002020202020', // g
+                'My first name is Greg and my last name is Hysen, what do ya know!', // h
+            ];
+            const a2 = [
+                /*'0xe41d2489571d322189246dafa5ebde1f4699f498', // i
+                true, // j*/
+                [new BigNumber(127), new BigNumber(14), new BigNumber(54)], // k
+                [
+                    'the little piping piper piped a piping pipper papper',
+                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+                ], // l
+                [
+                    '0x38745637834987324827439287423897238947239847',
+                    '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
+                    '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
+                ], // m
+                [
+                    [
+                        'some string',
+                        'some another string',
+                        'there are just too many stringsup in',
+                        'here',
+                        'yall ghonna make me lose my mind',
+                    ],
+                    [
+                        'the little piping piper piped a piping pipper papper',
+                        'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+                    ],
+                    [],
+                ], // n
+                [
+                    new BigNumber(4037824789),
+                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+                ], // o
+                [
+                    new BigNumber('239048320948320948230', 10),
+                    'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+                    /*[
+                        [
+                            '23432423342',
+                            'skdjfhdsjkfdhsfkjsdhfjkdshfdsjkfhsdjkfhsdjkfhdsjkfhdsjfhsdfjdshjkfsdhf',
+                            'sdfsdfdfdffsdf',
+                        ],
+                        [],
+                        [],
+                        ['23ehsdjkfhsiufhwfuefhesfhauhesufheuifhsefushfsufehfeuif'],
+                    ],*/
+                    '0xf74848484848484848484848484848484848483847576879809433994458585848932091',
+                    '0xe41d2489571d322189246dafa5ebde1f4699f498',
+                ], // p
+                /*[
+                    [
+                        new BigNumber('23904848320948230', 10),
+                        'akdhjasshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+                        [
+                            [
+                                '234324342',
+                                'skdjfhdsjkfdhsfkjsjkfhsdjkfhsdjkfhdsjkfhdsjfhsdfjdshjkfsdhf',
+                                'sdffdfdffsdf',
+                            ],
+                            [],
+                            [],
+                            ['23ehsdjkfhsiufhwfuefsufheuifhsefushfsufehfeuif'],
+                        ],
+                        '0xf7484848484848484848484848484876879809433994458585848932091',
+                        '0xe41d2489571d322189246dafa6ebde1f4699f498',
+                    ],
+                    [
+                        new BigNumber('23904832094832030', 10),
+                        'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdkdhsajkdhsadjk',
+                        [
+                            [
+                                '2343342',
+                                'skdjfhdsjkfdhsfkjsdhfjkdshfdsjkfhsdjkfhsdjkfhdssjfhsdfjdshjkfsdhf',
+                                'sdfsdfdfdffsf',
+                            ],
+                            [],
+                            [],
+                            ['jkfhsiufhwfuefhesfhauhesufhefeuif'],
+                        ],
+                        '0xf7484848484848484848484848484848484848384757687980943091',
+                        '0xe41d2489571d322189246dafa5ebde1f469af498',
+                    ],
+                    [],
+                    [],
+                ],*/
+            ];
+
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+
+            /*const expectedCalldata =
+                '0x89771c30af00000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
+            */
+
+            //expect(calldata).to.be.equal(expectedCalldata);
+
+            /*const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);*/
+        });
+
+        it.only('Simple ABI 2', async () => {
+            const method = new AbiEncoder.Method(crazyAbi);
+
+            const args = [
+                '0xaf', // e (bytes1)
+                '0x0001020304050607080911121314151617181920212223242526272829303132', // f (bytes32)
+                '0x616161616161616161616161616161616161616161616161616161616161616161616161616161611114f324567838475647382938475677448899338457668899002020202020', // g
+                'My first name is Greg and my last name is Hysen, what do ya know!', // h
+            ];
+
+            const calldata = method.encode(args);
+            const expectedCalldata =
+                '0x7ac2bd96af000000000000000000000000000000000000000000000000000000000000000001020304050607080911121314151617181920212223242526272829303132000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
         it('Yessir', async () => {
             const method = new AbiEncoder.Method(simpleAbi);
             const calldata = method.encode([new BigNumber(5), 'five']);
@@ -1291,7 +1619,7 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Bytes (Dynamic)', () => {
+    describe('Bytes (Dynamic)', () => {
         const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
         it('Less than 32 bytes', async () => {
             const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-- 
cgit v1.2.3


From 1600820deab0636d37a9a50025576a75ae8feeec Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 06:37:25 -0800
Subject: static array abi tests

---
 packages/order-utils/test/abi_encoder_test.ts | 131 ++++++++++++++++++--------
 1 file changed, 90 insertions(+), 41 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 95b6630ee..b27dc4793 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -72,6 +72,21 @@ const tupleAbi = {
     type: 'function',
 } as MethodAbi;
 
+const staticArrayAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 const crazyAbi = {
     constant: false,
     inputs: [
@@ -86,7 +101,7 @@ const crazyAbi = {
         {
             name: 'someInt32',
             type: 'int32',
-        },*/
+        },
         {
             name: 'someByte',
             type: 'byte',
@@ -102,7 +117,7 @@ const crazyAbi = {
         {
             name: 'someString',
             type: 'string',
-        },
+        },*/
         /*{
             name: 'someAddress',
             type: 'address',
@@ -112,12 +127,10 @@ const crazyAbi = {
             type: 'bool',
         },*/
 
-        /*
-
         {
             name: 'someStaticArray',
             type: 'uint8[3]',
-        },
+        } /*
         {
             name: 'someStaticArrayWithDynamicMembers',
             type: 'string[2]',
@@ -195,7 +208,7 @@ const crazyAbi = {
                     type: 'address',
                 },
             ],
-        },*/
+        },*/,
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -520,6 +533,7 @@ namespace AbiEncoder {
 
         public abstract assignValue(value: any): void;
         public abstract getSignature(): string;
+        public abstract isStatic(): boolean;
     }
 
     export abstract class StaticDataType extends DataType {
@@ -550,6 +564,10 @@ namespace AbiEncoder {
             return `address`;
         }
 
+        public isStatic(): boolean {
+            return true;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'address';
         }
@@ -572,6 +590,10 @@ namespace AbiEncoder {
             return 'bool';
         }
 
+        public isStatic(): boolean {
+            return true;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'bool';
         }
@@ -634,6 +656,10 @@ namespace AbiEncoder {
             this.assignHexValue(encodedValue);
         }
 
+        public isStatic(): boolean {
+            return true;
+        }
+
         public abstract getMaxValue(): BigNumber;
         public abstract getMinValue(): BigNumber;
     }
@@ -715,7 +741,7 @@ namespace AbiEncoder {
             if (valueBuf.byteLength > this.width) {
                 throw new Error(
                     `Tried to assign ${value} (${
-                        valueBuf.byteLength
+                    valueBuf.byteLength
                     } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
                 );
             } else if (value.length % 2 !== 0) {
@@ -734,6 +760,10 @@ namespace AbiEncoder {
             return `bytes${this.width}`;
         }
 
+        public isStatic(): boolean {
+            return true;
+        }
+
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
@@ -771,6 +801,10 @@ namespace AbiEncoder {
             return 'bytes';
         }
 
+        public isStatic(): boolean {
+            return false;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'bytes';
         }
@@ -797,6 +831,10 @@ namespace AbiEncoder {
             return 'string';
         }
 
+        public isStatic(): boolean {
+            return false;
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'string';
         }
@@ -807,6 +845,7 @@ namespace AbiEncoder {
         static UNDEFINED_LENGTH = new BigNumber(-1);
         length: BigNumber = SolArray.UNDEFINED_LENGTH;
         type: string = '[undefined]';
+        isLengthDefined: boolean;
 
         constructor(dataItem: DataItem) {
             super(dataItem);
@@ -825,10 +864,12 @@ namespace AbiEncoder {
             if (matches[2] === '') {
                 this.type = matches[1];
                 this.length = SolArray.UNDEFINED_LENGTH;
+                this.isLengthDefined = false;
                 return;
             }
 
             // Parse out array type/length and construct children
+            this.isLengthDefined = true;
             this.type = matches[1];
             this.length = new BigNumber(matches[2], 10);
             if (this.length.lessThan(0)) {
@@ -873,6 +914,10 @@ namespace AbiEncoder {
         }
 
         public getHexValue(): string {
+            if (this.isLengthDefined) {
+                return '0x';
+            }
+
             const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
             const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
             let valueBuf = lengthBuf;
@@ -888,6 +933,10 @@ namespace AbiEncoder {
             return valueHex;
         }
 
+        public isStatic(): boolean {
+            return this.isLengthDefined;
+        }
+
         public static matchGrammar(type: string): boolean {
             return this.matcher.test(type);
         }
@@ -1003,6 +1052,10 @@ namespace AbiEncoder {
             return signature;
         }
 
+        public isStatic(): boolean {
+            return false; // @TODO: True in every case or only when dynamic data?
+        }
+
         public static matchGrammar(type: string): boolean {
             return type === 'tuple';
         }
@@ -1057,6 +1110,10 @@ namespace AbiEncoder {
             return this.destDataType.getSignature();
         }
 
+        public isStatic(): boolean {
+            return true;
+        }
+
         public encodeToCalldata(calldata: Calldata): void {
             throw 2;
         }
@@ -1084,9 +1141,9 @@ namespace AbiEncoder {
 
         public static create(dataItem: DataItem, parentDataType: DataType): DataType {
             const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
-            if (dataType instanceof StaticDataType) {
+            if (dataType.isStatic()) {
                 return dataType;
-            } else if (dataType instanceof DynamicDataType) {
+            } else {
                 const pointer = new Pointer(dataType, parentDataType);
                 return pointer;
             }
@@ -1178,6 +1235,10 @@ namespace AbiEncoder {
             return this.getHexValue();
         }
 
+        public isStatic(): boolean {
+            return true;
+        }
+
         /*
         encodeOptimized(args: any[]): string {
             const calldata = new Memory();
@@ -1214,36 +1275,13 @@ namespace AbiEncoder {
 
 describe.only('ABI Encoder', () => {
     describe.only('Just a Greg, Eh', () => {
-        it.skip('Crazy ABI', async () => {
-            const method = new AbiEncoder.Method(crazyAbi);
+        it.only('Crazy ABI', async () => {
+            const method = new AbiEncoder.Method(staticArrayAbi);
             console.log(method.getSignature());
 
-            /*
-            (uint256 b,int256 c,int32 d,
-                bytes1 e,bytes32 f,
-                bytes g,string h,address i,bool j,uint8[3] k,string[2] l,bytes[] m, string[][] n, O o,P p, P[]) 
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
 
-                struct P {
-                    uint256 a;
-                    string b;
-                    string[] c;
-                    bytes d;
-                    address e;
-                }*/
-
-            const args = [
-                /*new BigNumber(437829473), // b
-                new BigNumber(-437829473), // c
-                new BigNumber(-14), // d*/
-                '0xaf', // e (bytes1)
-                '0x0001020304050607080911121314151617181920212223242526272829303132', // f (bytes32)
-                '0x616161616161616161616161616161616161616161616161616161616161616161616161616161611114f324567838475647382938475677448899338457668899002020202020', // g
-                'My first name is Greg and my last name is Hysen, what do ya know!', // h
-            ];
             const a2 = [
-                /*'0xe41d2489571d322189246dafa5ebde1f4699f498', // i
-                true, // j*/
-                [new BigNumber(127), new BigNumber(14), new BigNumber(54)], // k
                 [
                     'the little piping piper piped a piping pipper papper',
                     'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
@@ -1330,11 +1368,10 @@ describe.only('ABI Encoder', () => {
             console.log('*'.repeat(40));
             console.log(JSON.stringify(args));
 
-            /*const expectedCalldata =
-                '0x89771c30af00000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
-            */
+            const expectedCalldata =
+                '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
 
-            //expect(calldata).to.be.equal(expectedCalldata);
+            expect(calldata).to.be.equal(expectedCalldata);
 
             /*const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
             console.log(method.getSignature());
@@ -1346,8 +1383,20 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);*/
         });
 
-        it.only('Simple ABI 2', async () => {
-            const method = new AbiEncoder.Method(crazyAbi);
+        it.only('Static Array ABI', async () => {
+            const method = new AbiEncoder.Method(staticArrayAbi);
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            const expectedCalldata =
+                '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Simple ABI 2', async () => {
+            const method = new AbiEncoder.Method(simpleAbi2);
 
             const args = [
                 '0xaf', // e (bytes1)
-- 
cgit v1.2.3


From a13099bde3aa6a47516127ae7c7d9f78488a3911 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 07:27:14 -0800
Subject: hack for static arrays

---
 packages/order-utils/test/abi_encoder_test.ts | 134 +++++++++++++++-----------
 1 file changed, 78 insertions(+), 56 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index b27dc4793..b8f1d39ad 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -130,7 +130,7 @@ const crazyAbi = {
         {
             name: 'someStaticArray',
             type: 'uint8[3]',
-        } /*
+        },
         {
             name: 'someStaticArrayWithDynamicMembers',
             type: 'string[2]',
@@ -170,9 +170,9 @@ const crazyAbi = {
                     type: 'string',
                 },
                 //{
-              //      name: 'someStrArray',
-               //     type: 'string[]',
-               /// },
+                //      name: 'someStrArray',
+                //     type: 'string[]',
+                /// },
                 {
                     name: 'someBytes',
                     type: 'bytes',
@@ -889,6 +889,15 @@ namespace AbiEncoder {
             }
         }
 
+        // @TODO: HACKY -- shouldn't really have children for a 
+        public getChildren(): DataType[] {
+            if (this.isStatic()) {
+                return [];
+            } else {
+                return this.children;
+            }
+        }
+
         public assignValue(value: any[]) {
             // Sanity check length
             const valueLength = new BigNumber(value.length);
@@ -913,26 +922,40 @@ namespace AbiEncoder {
             }
         }
 
-        public getHexValue(): string {
-            if (this.isLengthDefined) {
-                return '0x';
-            }
-
+        private getHexValueDynamicArray(): string {
             const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
             const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
             let valueBuf = lengthBuf;
-            /*for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+
+            const valueHex = ethUtil.bufferToHex(valueBuf);
+            return valueHex;
+        }
+
+        private getHexValueStaticArray(): string {
+            let valueBuf = new Buffer("");
+
+            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
                 const idxNumber = idx.toNumber();
                 const childValueHex = this.children[idxNumber].getHexValue();
                 const childValueBuf = ethUtil.toBuffer(childValueHex);
                 valueBuf = Buffer.concat([valueBuf, childValueBuf]);
-            }*/
+
+                console.log(JSON.stringify(idx));
+            }
 
             // Convert value buffer to hex
             const valueHex = ethUtil.bufferToHex(valueBuf);
             return valueHex;
         }
 
+        public getHexValue(): string {
+            if (this.isLengthDefined) {
+                return this.getHexValueStaticArray();
+            } else {
+                return this.getHexValueDynamicArray();
+            }
+        }
+
         public isStatic(): boolean {
             return this.isLengthDefined;
         }
@@ -1275,56 +1298,54 @@ namespace AbiEncoder {
 
 describe.only('ABI Encoder', () => {
     describe.only('Just a Greg, Eh', () => {
-        it.only('Crazy ABI', async () => {
-            const method = new AbiEncoder.Method(staticArrayAbi);
+        it('Crazy ABI', async () => {
+            const method = new AbiEncoder.Method(crazyAbi);
             console.log(method.getSignature());
 
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-
-            const a2 = [
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)],
+            [
+                'the little piping piper piped a piping pipper papper',
+                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+            ], // l
+            [
+                '0x38745637834987324827439287423897238947239847',
+                '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
+                '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
+            ], // m
+            [
+                [
+                    'some string',
+                    'some another string',
+                    'there are just too many stringsup in',
+                    'here',
+                    'yall ghonna make me lose my mind',
+                ],
                 [
                     'the little piping piper piped a piping pipper papper',
                     'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-                ], // l
-                [
-                    '0x38745637834987324827439287423897238947239847',
-                    '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
-                    '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
-                ], // m
-                [
-                    [
-                        'some string',
-                        'some another string',
-                        'there are just too many stringsup in',
-                        'here',
-                        'yall ghonna make me lose my mind',
-                    ],
+                ],
+                [],
+            ], // n
+            [
+                new BigNumber(4037824789),
+                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+            ], // o
+            [
+                new BigNumber('239048320948320948230', 10),
+                'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+                /*[
                     [
-                        'the little piping piper piped a piping pipper papper',
-                        'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+                        '23432423342',
+                        'skdjfhdsjkfdhsfkjsdhfjkdshfdsjkfhsdjkfhsdjkfhdsjkfhdsjfhsdfjdshjkfsdhf',
+                        'sdfsdfdfdffsdf',
                     ],
                     [],
-                ], // n
-                [
-                    new BigNumber(4037824789),
-                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-                ], // o
-                [
-                    new BigNumber('239048320948320948230', 10),
-                    'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
-                    /*[
-                        [
-                            '23432423342',
-                            'skdjfhdsjkfdhsfkjsdhfjkdshfdsjkfhsdjkfhsdjkfhdsjkfhdsjfhsdfjdshjkfsdhf',
-                            'sdfsdfdfdffsdf',
-                        ],
-                        [],
-                        [],
-                        ['23ehsdjkfhsiufhwfuefhesfhauhesufheuifhsefushfsufehfeuif'],
-                    ],*/
-                    '0xf74848484848484848484848484848484848483847576879809433994458585848932091',
-                    '0xe41d2489571d322189246dafa5ebde1f4699f498',
-                ], // p
+                    [],
+                    ['23ehsdjkfhsiufhwfuefhesfhauhesufheuifhsefushfsufehfeuif'],
+                ],*/
+                '0xf74848484848484848484848484848484848483847576879809433994458585848932091',
+                '0xe41d2489571d322189246dafa5ebde1f4699f498',
+            ], // p
                 /*[
                     [
                         new BigNumber('23904848320948230', 10),
@@ -1367,11 +1388,12 @@ describe.only('ABI Encoder', () => {
             console.log(calldata);
             console.log('*'.repeat(40));
             console.log(JSON.stringify(args));
+            console.log(method.getSignature());
 
+            /*
             const expectedCalldata =
-                '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
-
-            expect(calldata).to.be.equal(expectedCalldata);
+                '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);*/
 
             /*const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
             console.log(method.getSignature());
-- 
cgit v1.2.3


From 637ab1076a4071505ea3d4797767826070a65e16 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 10:31:30 -0800
Subject: ABI Encoding for all combinations of arrays

---
 packages/order-utils/test/abi_encoder.ts      | 1098 ++++++++++++++++++++
 packages/order-utils/test/abi_encoder_test.ts | 1336 +------------------------
 packages/order-utils/test/abi_samples.ts      |  358 +++++++
 3 files changed, 1501 insertions(+), 1291 deletions(-)
 create mode 100644 packages/order-utils/test/abi_encoder.ts
 create mode 100644 packages/order-utils/test/abi_samples.ts

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
new file mode 100644
index 000000000..55b63b701
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -0,0 +1,1098 @@
+
+import * as chai from 'chai';
+import 'mocha';
+import ethUtil = require('ethereumjs-util');
+
+var _ = require('lodash');
+
+import { chaiSetup } from './utils/chai_setup';
+
+import { MethodAbi, DataItem } from 'ethereum-types';
+
+import { BigNumber } from '@0x/utils';
+import { bigNumberify } from 'ethers/utils';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+
+class Word {
+    private value: string;
+
+    constructor(value?: string) {
+        if (value === undefined) {
+            this.value = '';
+        } else {
+            this.value = value;
+        }
+    }
+
+    public set(value: string) {
+        if (value.length !== 64) {
+            throw `Tried to create word that is not 32 bytes: ${value}`;
+        }
+
+        this.value = value;
+    }
+
+    public get(): string {
+        return this.value;
+    }
+
+    public getAsHex(): string {
+        return `0x${this.value}`;
+    }
+}
+
+export enum CalldataSection {
+    NONE,
+    PARAMS,
+    DATA,
+}
+
+class Memblock {
+    private dataType: DataType;
+    private location: { calldataSection: CalldataSection; sectionOffset: BigNumber; offset: BigNumber };
+
+    constructor(dataType: DataType) {
+        this.dataType = dataType;
+        this.location = {
+            calldataSection: CalldataSection.NONE,
+            sectionOffset: new BigNumber(0),
+            offset: new BigNumber(0),
+        };
+    }
+
+    public getSize(): BigNumber {
+        return new BigNumber(ethUtil.toBuffer(this.dataType.getHexValue()).byteLength);
+    }
+
+    public assignLocation(calldataSection: CalldataSection, sectionOffset: BigNumber, offset: BigNumber) {
+        this.location.calldataSection = calldataSection;
+        this.location.sectionOffset = sectionOffset;
+        this.location.offset = offset;
+    }
+
+    public get(): string {
+        return ethUtil.stripHexPrefix(this.dataType.getHexValue());
+    }
+
+    public getOffset(): BigNumber {
+        return this.location.offset;
+    }
+
+    public getAbsoluteOffset(): BigNumber {
+        return this.location.sectionOffset.plus(this.location.offset);
+    }
+
+    public getSection(): CalldataSection {
+        return this.location.calldataSection;
+    }
+}
+
+interface BindList {
+    [key: string]: Memblock;
+}
+
+export class Calldata {
+    private selector: string;
+    private params: Memblock[];
+    private data: Memblock[];
+    private dataOffset: BigNumber;
+    private currentDataOffset: BigNumber;
+    private currentParamOffset: BigNumber;
+    private bindList: BindList;
+
+    constructor(selector: string, nParams: number) {
+        this.selector = selector;
+        this.params = [];
+        this.data = [];
+        const evmWordSize = 32;
+        this.dataOffset = new BigNumber(nParams).times(evmWordSize);
+        this.currentDataOffset = new BigNumber(0);
+        this.currentParamOffset = new BigNumber(0);
+        this.bindList = {};
+    }
+
+    public bind(dataType: DataType, section: CalldataSection) {
+        if (dataType.getId() in this.bindList) {
+            throw `Rebind on ${dataType.getId()}`;
+        }
+        const memblock = new Memblock(dataType);
+        switch (section) {
+            case CalldataSection.PARAMS:
+                this.params.push(memblock);
+                memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
+
+                console.log(`Binding ${dataType.getDataItem().name} to PARAMS at ${this.currentParamOffset}`);
+                this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
+                break;
+
+            case CalldataSection.DATA:
+                this.data.push(memblock);
+                memblock.assignLocation(section, this.dataOffset, this.currentDataOffset);
+
+                console.log(
+                    `Binding ${dataType.getDataItem().name} to DATA at ${memblock
+                        .getAbsoluteOffset()
+                        .toString(16)}`,
+                );
+                this.currentDataOffset = this.currentDataOffset.plus(memblock.getSize());
+                break;
+
+            default:
+                throw `Unrecognized calldata section: ${section}`;
+        }
+
+        this.bindList[dataType.getId()] = memblock;
+        dataType.rbind(memblock);
+    }
+
+    public getHexValue(): string {
+        let hexValue = `${this.selector}`;
+        _.each(this.params, (memblock: Memblock) => {
+            hexValue += memblock.get();
+        });
+        _.each(this.data, (memblock: Memblock) => {
+            hexValue += memblock.get();
+        });
+
+        return hexValue;
+    }
+}
+
+export abstract class DataType {
+    private dataItem: DataItem;
+    private hexValue: string;
+    protected memblock: Memblock | undefined;
+    protected children: DataType[];
+
+    constructor(dataItem: DataItem) {
+        this.dataItem = dataItem;
+        this.hexValue = '0x';
+        this.memblock = undefined;
+        this.children = [];
+    }
+
+    protected assignHexValue(hexValue: string) {
+        this.hexValue = hexValue;
+    }
+
+    public getHexValue(): string {
+        return this.hexValue;
+    }
+
+    public getDataItem(): DataItem {
+        return this.dataItem;
+    }
+
+    public rbind(memblock: Memblock) {
+        this.memblock = memblock;
+    }
+
+    public bind(calldata: Calldata, section: CalldataSection) {
+        calldata.bind(this, section);
+        _.each(this.getChildren(), (child: DataType) => {
+            child.bind(calldata, CalldataSection.DATA);
+        });
+    }
+
+    public getId(): string {
+        return this.dataItem.name;
+    }
+
+    public getOffset(): BigNumber {
+        if (this.memblock === undefined) return new BigNumber(0);
+        return this.memblock.getOffset();
+    }
+
+    public getAbsoluteOffset(): BigNumber {
+        if (this.memblock === undefined) return new BigNumber(0);
+        return this.memblock.getAbsoluteOffset();
+    }
+    /*
+        public getSize(): BigNumber {
+            if (this.memblock === undefined) return new BigNumber(0);
+            return this.memblock.getSize();
+        }
+        */
+
+    public getChildren(): DataType[] {
+        return this.children;
+    }
+
+    public getSize(): BigNumber {
+        return this.getHeaderSize().plus(this.getBodySize());
+    }
+
+    public abstract assignValue(value: any): void;
+    public abstract getSignature(): string;
+    public abstract isStatic(): boolean;
+    public abstract getHeaderSize(): BigNumber;
+    public abstract getBodySize(): BigNumber;
+}
+
+export abstract class StaticDataType extends DataType {
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+    }
+}
+
+export abstract class DynamicDataType extends DataType {
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+    }
+}
+
+export class Address extends StaticDataType {
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        expect(Address.matchGrammar(dataItem.type)).to.be.true();
+    }
+
+    public assignValue(value: string) {
+        const evmWordWidth = 32;
+        const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth));
+        this.assignHexValue(hexValue);
+    }
+
+    public getSignature(): string {
+        return `address`;
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(32);
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'address';
+    }
+}
+
+export class Bool extends StaticDataType {
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        expect(Bool.matchGrammar(dataItem.type)).to.be.true();
+    }
+
+    public assignValue(value: boolean) {
+        const evmWordWidth = 32;
+        const encodedValue = value === true ? '0x1' : '0x0';
+        const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth));
+        this.assignHexValue(hexValue);
+    }
+
+    public getSignature(): string {
+        return 'bool';
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(32);
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bool';
+    }
+}
+
+abstract class Number extends StaticDataType {
+    static MAX_WIDTH: number = 256;
+    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
+    width: number = Number.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem, matcher: RegExp) {
+        super(dataItem);
+        const matches = matcher.exec(dataItem.type);
+        expect(matches).to.be.not.null();
+        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
+            this.width = parseInt(matches[1]);
+        } else {
+            this.width = 256;
+        }
+    }
+
+    public assignValue(value: BigNumber) {
+        if (value.greaterThan(this.getMaxValue())) {
+            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+        } else if (value.lessThan(this.getMinValue())) {
+            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+        }
+
+        const hexBase = 16;
+        const evmWordWidth = 32;
+        let valueBuf: Buffer;
+        if (value.greaterThanOrEqualTo(0)) {
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
+        } else {
+            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
+            // Step 1/3: Convert value to positive binary string
+            const binBase = 2;
+            const valueBin = value.times(-1).toString(binBase);
+
+            // Step 2/3: Invert binary value
+            const bitsInEvmWord = 256;
+            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
+            _.each(valueBin, (bit: string) => {
+                invertedValueBin += bit === '1' ? '0' : '1';
+            });
+            const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+            // Step 3/3: Add 1 to inverted value
+            // The result is the two's-complement represent of the input value.
+            const negativeValue = invertedValue.plus(1);
+
+            // Convert the negated value to a hex string
+            valueBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
+                evmWordWidth,
+            );
+        }
+
+        const encodedValue = ethUtil.bufferToHex(valueBuf);
+        this.assignHexValue(encodedValue);
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(32);
+    }
+
+    public abstract getMaxValue(): BigNumber;
+    public abstract getMinValue(): BigNumber;
+}
+
+export class Int extends Number {
+    static matcher = RegExp(
+        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Int.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).times(-1);
+    }
+
+    public getSignature(): string {
+        return `int${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class UInt extends Number {
+    static matcher = RegExp(
+        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, UInt.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getSignature(): string {
+        return `uint${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Byte extends StaticDataType {
+    static matcher = RegExp(
+        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+    );
+
+    static DEFAULT_WIDTH = 1;
+    width: number = Byte.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        const matches = Byte.matcher.exec(dataItem.type);
+        expect(matches).to.be.not.null();
+        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
+            this.width = parseInt(matches[2]);
+        } else {
+            this.width = Byte.DEFAULT_WIDTH;
+        }
+    }
+
+    public assignValue(value: string | Buffer) {
+        // Convert value into a buffer and do bounds checking
+        const valueBuf = ethUtil.toBuffer(value);
+        if (valueBuf.byteLength > this.width) {
+            throw new Error(
+                `Tried to assign ${value} (${
+                valueBuf.byteLength
+                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
+            );
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        // Store value as hex
+        const evmWordWidth = 32;
+        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
+        const hexValue = ethUtil.bufferToHex(paddedValue);
+        this.assignHexValue(hexValue);
+    }
+
+    public getSignature(): string {
+        // Note that `byte` reduces to `bytes1`
+        return `bytes${this.width}`;
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(32);
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Bytes extends DynamicDataType {
+    static UNDEFINED_LENGTH = new BigNumber(-1);
+    length: BigNumber = Bytes.UNDEFINED_LENGTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
+    }
+
+    public assignValue(value: string | Buffer) {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const paddedValueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
+        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
+        const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
+
+        this.assignHexValue(encodedValue);
+    }
+
+    public getSignature(): string {
+        return 'bytes';
+    }
+
+    public isStatic(): boolean {
+        return false;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(this.getHexValue().length);
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bytes';
+    }
+}
+
+export class SolString extends DynamicDataType {
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        expect(SolString.matchGrammar(dataItem.type)).to.be.true();
+    }
+
+    public assignValue(value: string) {
+        const wordsForValue = Math.ceil(value.length / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+        const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
+
+        this.assignHexValue(encodedValue);
+    }
+
+    public getSignature(): string {
+        return 'string';
+    }
+
+    public isStatic(): boolean {
+        return false;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(this.getHexValue().length);
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'string';
+    }
+}
+
+export class SolArray extends DynamicDataType {
+    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    static UNDEFINED_LENGTH = new BigNumber(-1);
+    length: BigNumber = SolArray.UNDEFINED_LENGTH;
+    type: string = '[undefined]';
+    isLengthDefined: boolean;
+    isStaticArray: boolean; // An array is dynamic if it's lenghth is undefined or if its children are dynamic.
+    private elements: DataType[];
+
+    /*
+    --- Layout 1: Fixed Length Array with Static Types ---
+    Elem1, Elem2, ..., ElemN
+
+    --- Layout 2: Fixed Length Array with Dynamic Types ---
+    PtrToArray, ..., Elem1, Elem2, ..., ElemN
+
+    --- Layout 3: Dynamic Length Array with Static Types ---
+    PtrToArray, ..., ArrayLength, Elem1, Elem2, ..., ElemN
+
+    --- Layout 4: Dynamic Length Array with Dynamic Types ---
+    PtrToArray, ..., ArrayLength, PtrToElem1, PtrToElem2, ..., PtrToElemN, ..., Elem1, Elem2, ..., ElemN
+    */
+
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        const matches = SolArray.matcher.exec(dataItem.type);
+        expect(matches).to.be.not.null();
+        console.log(JSON.stringify(matches));
+        if (matches === null || matches.length !== 3) {
+            throw new Error(`Could not parse array: ${dataItem.type}`);
+        } else if (matches[1] === undefined) {
+            throw new Error(`Could not parse array type: ${dataItem.type}`);
+        } else if (matches[2] === undefined) {
+            throw new Error(`Could not parse array length: ${dataItem.type}`);
+        }
+
+        this.elements = [];
+
+        // Check if length is undefined
+        if (matches[2] === '') {
+            this.type = matches[1];
+            this.length = SolArray.UNDEFINED_LENGTH;
+            this.isLengthDefined = false;
+            this.isStaticArray = false;
+            return;
+        }
+
+        // Parse out array type/length and construct children
+        this.isLengthDefined = true;
+        this.type = matches[1];
+        this.length = new BigNumber(matches[2], 10);
+        if (this.length.lessThan(1)) {
+            throw new Error(`Bad array length: ${JSON.stringify(this.length)}`);
+        }
+        this.constructChildren();
+
+        // Check if we're static or not
+        this.isStaticArray = !(this.elements[0] instanceof Pointer);  //this.elements[0].isStatic();
+        //throw new Error(`Am I static? ${this.isStaticArray}`);
+    }
+
+    private constructChildren() {
+        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+            const childDataItem = {
+                type: this.type,
+                name: `${this.getDataItem().name}[${idx.toString(10)}]`,
+            } as DataItem;
+            const child = DataTypeFactory.create(childDataItem, this);
+            this.elements.push(child);
+            if (child instanceof Pointer) {
+                const pointsTo = child.getChildren()[0];
+                console.log(JSON.stringify(pointsTo));
+                this.children.push(pointsTo); // DataType pointing to
+            }
+        }
+    }
+
+    // @TODO: HACKY -- shouldn't really have children for a 
+    /*
+    public getChildren(): DataType[] {
+        if (this.isStatic()) {
+            return [];
+        } else {
+            return this.children;
+        }
+    }*/
+
+    public assignValue(value: any[]) {
+        // Sanity check length
+        const valueLength = new BigNumber(value.length);
+        if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
+            throw new Error(
+                `Expected array of length ${JSON.stringify(this.length)}, but got array of length ${JSON.stringify(
+                    valueLength,
+                )}`,
+            );
+        }
+
+        // Assign length if not already set
+        if (this.length === SolArray.UNDEFINED_LENGTH) {
+            this.length = valueLength;
+            this.constructChildren();
+        }
+
+        // Assign values to children
+        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+            const idxNumber = idx.toNumber();
+            this.elements[idxNumber].assignValue(value[idxNumber]);
+        }
+    }
+
+    public getHexValue(): string {
+        let valueBuf = new Buffer("");
+
+        if (this.isLengthDefined === false) {
+            // Must include the array length
+            const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
+            const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
+            valueBuf = lengthBuf;
+        }
+
+        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+            const idxNumber = idx.toNumber();
+            const childValueHex = this.elements[idxNumber].getHexValue();
+            const childValueBuf = ethUtil.toBuffer(childValueHex);
+            valueBuf = Buffer.concat([valueBuf, childValueBuf]);
+        }
+
+        // Convert value buffer to hex
+        const valueHex = ethUtil.bufferToHex(valueBuf);
+        return valueHex;
+    }
+
+    public isStatic(): boolean {
+        return this.isStaticArray;
+    }
+
+    public getHeaderSize(): BigNumber {
+        let size = new BigNumber(0);
+        if (!this.isLengthDefined) {
+            size = new BigNumber(32); // stores length of bytes
+        }
+        return size;
+    }
+
+    public getBodySize(): BigNumber {
+        const evmWordWidth = new BigNumber(32);
+        const body = this.length.times(evmWordWidth);
+        return body;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+
+    public getSignature(): string {
+        let type = this.type;
+        if (this.type === 'tuple') {
+            let tupleDataItem = {
+                type: 'tuple',
+                name: 'N/A',
+            } as DataItem;
+            const tupleComponents = this.getDataItem().components;
+            if (tupleComponents !== undefined) {
+                tupleDataItem.components = tupleComponents;
+            }
+            const tuple = new Tuple(tupleDataItem);
+            type = tuple.getSignature();
+        }
+
+        if (this.length.equals(SolArray.UNDEFINED_LENGTH)) {
+            return `${type}[]`;
+        }
+        return `${type}[${this.length}]`;
+    }
+}
+
+export class Tuple extends DynamicDataType {
+    private length: BigNumber;
+    private childMap: { [key: string]: number };
+
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
+        this.length = new BigNumber(0);
+        this.childMap = {};
+        if (dataItem.components !== undefined) {
+            this.constructChildren(dataItem.components);
+            this.length = new BigNumber(dataItem.components.length);
+        } else {
+            throw new Error('Components undefined');
+        }
+    }
+
+    private constructChildren(dataItems: DataItem[]) {
+        _.each(dataItems, (dataItem: DataItem) => {
+            const childDataItem = {
+                type: dataItem.type,
+                name: `${this.getDataItem().name}.${dataItem.name}`,
+            } as DataItem;
+            const child = DataTypeFactory.create(childDataItem, this);
+            this.childMap[dataItem.name] = this.children.length;
+            this.children.push(child);
+        });
+    }
+
+    private assignValueFromArray(value: any[]) {
+        // Sanity check length
+        const valueLength = new BigNumber(value.length);
+        if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
+            throw new Error(
+                `Expected array of ${JSON.stringify(
+                    this.length,
+                )} elements, but got array of length ${JSON.stringify(valueLength)}`,
+            );
+        }
+
+        // Assign values to children
+        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+            const idxNumber = idx.toNumber();
+            this.children[idxNumber].assignValue(value[idxNumber]);
+        }
+    }
+
+    private assignValueFromObject(obj: object) {
+        let childMap = _.cloneDeep(this.childMap);
+        _.forOwn(obj, (value: any, key: string) => {
+            if (key in childMap === false) {
+                throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
+            }
+            this.children[this.childMap[key]].assignValue(value);
+            delete childMap[key];
+        });
+
+        if (Object.keys(childMap).length !== 0) {
+            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+        }
+    }
+
+    public assignValue(value: any[] | object) {
+        if (value instanceof Array) {
+            this.assignValueFromArray(value);
+        } else if (typeof value === 'object') {
+            this.assignValueFromObject(value);
+        } else {
+            throw new Error(`Unexpected type for ${value}`);
+        }
+    }
+
+    public getHexValue(): string {
+        return '0x';
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        const evmWordWidth = new BigNumber(32);
+        const size = this.length.times(evmWordWidth);
+        return size;
+    }
+
+    public getSignature(): string {
+        // Compute signature
+        let signature = `(`;
+        _.each(this.children, (child: DataType, i: number) => {
+            signature += child.getSignature();
+            if (i < this.children.length - 1) {
+                signature += ',';
+            }
+        });
+        signature += ')';
+        return signature;
+    }
+
+    public isStatic(): boolean {
+        return false; // @TODO: True in every case or only when dynamic data?
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'tuple';
+    }
+}
+
+/* TODO
+class Fixed extends StaticDataType {}
+
+class UFixed extends StaticDataType {}*/
+
+export class Pointer extends StaticDataType {
+    destDataType: DynamicDataType;
+    parentDataType: DataType;
+
+    constructor(destDataType: DynamicDataType, parentDataType: DataType) {
+        const destDataItem = destDataType.getDataItem();
+        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
+        super(dataItem);
+        this.destDataType = destDataType;
+        this.parentDataType = parentDataType;
+        this.children.push(destDataType);
+    }
+
+    /*
+    public assignValue(destDataType: DynamicDataType) {
+        this.destDataType = destDataType;
+    }*/
+
+    public assignValue(value: any) {
+        this.destDataType.assignValue(value);
+    }
+
+    public getHexValue(): string {
+        console.log(
+            '*'.repeat(40),
+            this.destDataType.getAbsoluteOffset().toString(16),
+            '^'.repeat(150),
+            this.parentDataType.getAbsoluteOffset().toString(16),
+        );
+
+        let offset = this.destDataType
+            .getAbsoluteOffset()
+            .minus(this.parentDataType.getAbsoluteOffset())
+            .minus(this.parentDataType.getHeaderSize());
+
+        console.log("OFFSET == ", JSON.stringify(offset), " or in hex -- 0x", offset.toString(16));
+
+        const hexBase = 16;
+        const evmWordWidth = 32;
+        const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${offset.toString(hexBase)}`), evmWordWidth);
+        const encodedValue = ethUtil.bufferToHex(valueBuf);
+        return encodedValue;
+    }
+
+    public getSignature(): string {
+        return this.destDataType.getSignature();
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+
+    public getHeaderSize(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        return new BigNumber(32);
+    }
+
+}
+
+export class DataTypeFactory {
+    public static mapDataItemToDataType(dataItem: DataItem): DataType {
+        console.log(`Type: ${dataItem.type}`);
+
+        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
+        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
+        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
+        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
+        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
+        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
+        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
+        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
+        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
+        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
+
+        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+    }
+
+    public static create(dataItem: DataItem, parentDataType: DataType): DataType {
+        const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
+        if (dataType.isStatic()) {
+            return dataType;
+        } else {
+            const pointer = new Pointer(dataType, parentDataType);
+            return pointer;
+        }
+
+        throw new Error(`Unrecognized instance type: '${dataType}'`);
+    }
+}
+
+class Queue<T> {
+    private store: T[] = [];
+    push(val: T) {
+        this.store.push(val);
+    }
+    pop(): T | undefined {
+        return this.store.shift();
+    }
+}
+
+export class Method extends DataType {
+    name: string;
+    params: DataType[];
+    private signature: string;
+    selector: string;
+
+    constructor(abi: MethodAbi) {
+        super({ type: 'method', name: abi.name });
+        this.name = abi.name;
+        this.params = [];
+
+        _.each(abi.inputs, (input: DataItem) => {
+            this.params.push(DataTypeFactory.create(input, this));
+        });
+
+        // Compute signature
+        this.signature = `${this.name}(`;
+        _.each(this.params, (param: DataType, i: number) => {
+            this.signature += param.getSignature();
+            if (i < this.params.length - 1) {
+                this.signature += ',';
+            }
+        });
+        this.signature += ')';
+
+        // Compute selector
+        this.selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(this.signature).slice(0, 4)));
+
+        console.log(`--SIGNATURE--\n${this.signature}\n---------\n`);
+        console.log(`--SELECTOR--\n${this.selector}\n---------\n`);
+    }
+
+    public getSignature(): string {
+        return this.signature;
+    }
+
+    public assignValue(args: any[]) {
+        _.each(this.params, (param: DataType, i: number) => {
+            // Assign value to parameter
+            try {
+                param.assignValue(args[i]);
+            } catch (e) {
+                console.log('Failed to assign to ', param.getDataItem().name);
+                throw e;
+            }
+
+            if (param instanceof Pointer) {
+                this.children.push(param.getChildren()[0]);
+            }
+        });
+    }
+
+    public getHexValue(): string {
+        let value = "";
+        _.each(this.params, (param: DataType) => {
+            value += param.getHexValue();
+        });
+
+        return value;
+    }
+
+    public encode(args: any[]): string {
+        this.assignValue(args);
+        const calldata = new Calldata(this.selector, this.params.length);
+        this.bind(calldata, CalldataSection.PARAMS);
+
+        return calldata.getHexValue();
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+
+    public getHeaderSize(): BigNumber {
+        // Exclude selector
+        return new BigNumber(0);
+    }
+
+    public getBodySize(): BigNumber {
+        const nParams = new BigNumber(this.params.length);
+        const evmWordWidth = new BigNumber(32);
+        const size = nParams.times(evmWordWidth);
+        return size;
+    }
+
+    /*
+    encodeOptimized(args: any[]): string {
+        const calldata = new Memory();
+        // Assign values
+        optimizableParams : StaticDataType = [];
+        _.each(this.params, function(args: any[], i: number, param: DataType) {
+            param.assignValue(args[i]);
+            if (param instanceof DynamicDataType) {
+
+            }
+        });
+
+        // Find non-parameter leaves
+
+
+        return '';
+    } */
+
+    /*
+    decode(rawCalldata: string): any[] {
+        const calldata = new Calldata(this.name, this.params.length);
+        calldata.assignRaw(rawCalldata);
+        let args: any[];
+        let params = this.params;
+        _.each(params, function(args: any[], i: number, param: DataType) {
+            param.decodeFromCalldata(calldata);
+            args.push(param.getValue());
+        });
+
+        return args;
+    }*/
+}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index b8f1d39ad..315537226 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -12,1294 +12,18 @@ import { MethodAbi, DataItem } from 'ethereum-types';
 
 import { BigNumber } from '@0x/utils';
 import { assert } from '@0x/order-utils/src/assert';
-
-const simpleAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'greg',
-            type: 'uint256',
-        },
-        {
-            name: 'gregStr',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-const stringAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'greg',
-            type: 'string[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-const tupleAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-const staticArrayAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[3]',
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-const crazyAbi = {
-    constant: false,
-    inputs: [
-        /*{
-            name: 'someUInt256',
-            type: 'uint256',
-        },
-        {
-            name: 'someInt256',
-            type: 'int256',
-        },
-        {
-            name: 'someInt32',
-            type: 'int32',
-        },
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someBytes32',
-            type: 'bytes32',
-        },
-        {
-            name: 'someBytes',
-            type: 'bytes',
-        },
-        {
-            name: 'someString',
-            type: 'string',
-        },*/
-        /*{
-            name: 'someAddress',
-            type: 'address',
-        },
-        {
-            name: 'someBool',
-            type: 'bool',
-        },*/
-
-        {
-            name: 'someStaticArray',
-            type: 'uint8[3]',
-        },
-        {
-            name: 'someStaticArrayWithDynamicMembers',
-            type: 'string[2]',
-        },
-        {
-            name: 'someDynamicArrayWithDynamicMembers',
-            type: 'bytes[]',
-        },
-        {
-            name: 'some2DArray',
-            type: 'string[][]',
-        },
-        {
-            name: 'someTuple',
-            type: 'tuple',
-            components: [
-                {
-                    name: 'someUint32',
-                    type: 'uint32',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-            ],
-        },
-        {
-            name: 'someTupleWithDynamicTypes',
-            type: 'tuple',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                //{
-                //      name: 'someStrArray',
-                //     type: 'string[]',
-                /// },
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        } /*,
-        {
-            name: 'someArrayOfTuplesWithDynamicTypes',
-            type: 'tuple[]',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                {
-                    name: 'someStrArray',
-                    type: 'string[]',
-                },
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        },*/,
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-const simpleAbi2 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someBytes32',
-            type: 'bytes32',
-        },
-        {
-            name: 'someBytes',
-            type: 'bytes',
-        },
-        {
-            name: 'someString',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-const fillOrderAbi = {
-    constant: false,
-    inputs: [
-        {
-            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: 'order',
-            type: 'tuple',
-        },
-        {
-            name: 'takerAssetFillAmount',
-            type: 'uint256',
-        },
-        {
-            name: 'salt',
-            type: 'uint256',
-        },
-        {
-            name: 'orderSignature',
-            type: 'bytes',
-        },
-        {
-            name: 'takerSignature',
-            type: 'bytes',
-        },
-    ],
-    name: 'fillOrder',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
+import * as AbiEncoder from './abi_encoder';
+import * as AbiSamples from './abi_samples';
 
 chaiSetup.configure();
 const expect = chai.expect;
 
-namespace AbiEncoder {
-    class Word {
-        private value: string;
-
-        constructor(value?: string) {
-            if (value === undefined) {
-                this.value = '';
-            } else {
-                this.value = value;
-            }
-        }
-
-        public set(value: string) {
-            if (value.length !== 64) {
-                throw `Tried to create word that is not 32 bytes: ${value}`;
-            }
-
-            this.value = value;
-        }
-
-        public get(): string {
-            return this.value;
-        }
-
-        public getAsHex(): string {
-            return `0x${this.value}`;
-        }
-    }
-
-    export enum CalldataSection {
-        NONE,
-        PARAMS,
-        DATA,
-    }
-
-    class Memblock {
-        private dataType: DataType;
-        private location: { calldataSection: CalldataSection; sectionOffset: BigNumber; offset: BigNumber };
-
-        constructor(dataType: DataType) {
-            this.dataType = dataType;
-            this.location = {
-                calldataSection: CalldataSection.NONE,
-                sectionOffset: new BigNumber(0),
-                offset: new BigNumber(0),
-            };
-        }
-
-        public getSize(): BigNumber {
-            return new BigNumber(ethUtil.toBuffer(this.dataType.getHexValue()).byteLength);
-        }
-
-        public assignLocation(calldataSection: CalldataSection, sectionOffset: BigNumber, offset: BigNumber) {
-            this.location.calldataSection = calldataSection;
-            this.location.sectionOffset = sectionOffset;
-            this.location.offset = offset;
-        }
-
-        public get(): string {
-            return ethUtil.stripHexPrefix(this.dataType.getHexValue());
-        }
-
-        public getOffset(): BigNumber {
-            return this.location.offset;
-        }
-
-        public getAbsoluteOffset(): BigNumber {
-            return this.location.sectionOffset.plus(this.location.offset);
-        }
-
-        public getSection(): CalldataSection {
-            return this.location.calldataSection;
-        }
-    }
-
-    interface BindList {
-        [key: string]: Memblock;
-    }
-
-    export class Calldata {
-        private selector: string;
-        private params: Memblock[];
-        private data: Memblock[];
-        private dataOffset: BigNumber;
-        private currentDataOffset: BigNumber;
-        private currentParamOffset: BigNumber;
-        private bindList: BindList;
-
-        constructor(selector: string, nParams: number) {
-            this.selector = selector;
-            console.log(this.selector);
-            this.params = [];
-            this.data = [];
-            const evmWordSize = 32;
-            this.dataOffset = new BigNumber(nParams).times(evmWordSize);
-            this.currentDataOffset = new BigNumber(0);
-            this.currentParamOffset = new BigNumber(0);
-            this.bindList = {};
-        }
-
-        public bind(dataType: DataType, section: CalldataSection) {
-            if (dataType.getId() in this.bindList) {
-                throw `Rebind on ${dataType.getId()}`;
-            }
-            const memblock = new Memblock(dataType);
-            switch (section) {
-                case CalldataSection.PARAMS:
-                    this.params.push(memblock);
-                    memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
-
-                    console.log(`Binding ${dataType.getDataItem().name} to PARAMS at ${this.currentParamOffset}`);
-                    this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
-                    break;
-
-                case CalldataSection.DATA:
-                    this.data.push(memblock);
-                    memblock.assignLocation(section, this.dataOffset, this.currentDataOffset);
-
-                    console.log(
-                        `Binding ${dataType.getDataItem().name} to DATA at ${memblock
-                            .getAbsoluteOffset()
-                            .toString(16)}`,
-                    );
-                    this.currentDataOffset = this.currentDataOffset.plus(memblock.getSize());
-                    break;
-
-                default:
-                    throw `Unrecognized calldata section: ${section}`;
-            }
-
-            this.bindList[dataType.getId()] = memblock;
-            dataType.rbind(memblock);
-        }
-
-        public getHexValue(): string {
-            let hexValue = `${this.selector}`;
-            _.each(this.params, (memblock: Memblock) => {
-                hexValue += memblock.get();
-            });
-            _.each(this.data, (memblock: Memblock) => {
-                hexValue += memblock.get();
-            });
-
-            return hexValue;
-        }
-    }
-
-    export abstract class DataType {
-        private dataItem: DataItem;
-        private hexValue: string;
-        protected memblock: Memblock | undefined;
-        protected children: DataType[];
-
-        constructor(dataItem: DataItem) {
-            this.dataItem = dataItem;
-            this.hexValue = '0x';
-            this.memblock = undefined;
-            this.children = [];
-        }
-
-        protected assignHexValue(hexValue: string) {
-            this.hexValue = hexValue;
-        }
-
-        public getHexValue(): string {
-            return this.hexValue;
-        }
-
-        public getDataItem(): DataItem {
-            return this.dataItem;
-        }
-
-        public rbind(memblock: Memblock) {
-            this.memblock = memblock;
-        }
-
-        public bind(calldata: Calldata, section: CalldataSection) {
-            calldata.bind(this, section);
-        }
-
-        public getId(): string {
-            return this.dataItem.name;
-        }
-
-        public getOffset(): BigNumber {
-            if (this.memblock === undefined) return new BigNumber(0);
-            return this.memblock.getOffset();
-        }
-
-        public getAbsoluteOffset(): BigNumber {
-            if (this.memblock === undefined) return new BigNumber(0);
-            return this.memblock.getAbsoluteOffset();
-        }
-
-        public getSize(): BigNumber {
-            if (this.memblock === undefined) return new BigNumber(0);
-            return this.memblock.getSize();
-        }
-
-        public getChildren(): DataType[] {
-            return this.children;
-        }
-
-        public abstract assignValue(value: any): void;
-        public abstract getSignature(): string;
-        public abstract isStatic(): boolean;
-    }
-
-    export abstract class StaticDataType extends DataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-        }
-    }
-
-    export abstract class DynamicDataType extends DataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-        }
-    }
-
-    export class Address extends StaticDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Address.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            const evmWordWidth = 32;
-            const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth));
-            this.assignHexValue(hexValue);
-        }
-
-        public getSignature(): string {
-            return `address`;
-        }
-
-        public isStatic(): boolean {
-            return true;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'address';
-        }
-    }
-
-    export class Bool extends StaticDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Bool.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: boolean) {
-            const evmWordWidth = 32;
-            const encodedValue = value === true ? '0x1' : '0x0';
-            const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth));
-            this.assignHexValue(hexValue);
-        }
-
-        public getSignature(): string {
-            return 'bool';
-        }
-
-        public isStatic(): boolean {
-            return true;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'bool';
-        }
-    }
-
-    abstract class Number extends StaticDataType {
-        static MAX_WIDTH: number = 256;
-        static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
-        width: number = Number.DEFAULT_WIDTH;
-
-        constructor(dataItem: DataItem, matcher: RegExp) {
-            super(dataItem);
-            const matches = matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
-                this.width = parseInt(matches[1]);
-            } else {
-                this.width = 256;
-            }
-        }
-
-        public assignValue(value: BigNumber) {
-            if (value.greaterThan(this.getMaxValue())) {
-                throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
-            } else if (value.lessThan(this.getMinValue())) {
-                throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
-            }
-
-            const hexBase = 16;
-            const evmWordWidth = 32;
-            let valueBuf: Buffer;
-            if (value.greaterThanOrEqualTo(0)) {
-                valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
-            } else {
-                // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
-                // Step 1/3: Convert value to positive binary string
-                const binBase = 2;
-                const valueBin = value.times(-1).toString(binBase);
-
-                // Step 2/3: Invert binary value
-                const bitsInEvmWord = 256;
-                let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
-                _.each(valueBin, (bit: string) => {
-                    invertedValueBin += bit === '1' ? '0' : '1';
-                });
-                const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-                // Step 3/3: Add 1 to inverted value
-                // The result is the two's-complement represent of the input value.
-                const negativeValue = invertedValue.plus(1);
-
-                // Convert the negated value to a hex string
-                valueBuf = ethUtil.setLengthLeft(
-                    ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
-                    evmWordWidth,
-                );
-            }
-
-            const encodedValue = ethUtil.bufferToHex(valueBuf);
-            this.assignHexValue(encodedValue);
-        }
-
-        public isStatic(): boolean {
-            return true;
-        }
-
-        public abstract getMaxValue(): BigNumber;
-        public abstract getMinValue(): BigNumber;
-    }
-
-    export class Int extends Number {
-        static matcher = RegExp(
-            '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-        );
-
-        constructor(dataItem: DataItem) {
-            super(dataItem, Int.matcher);
-        }
-
-        public getMaxValue(): BigNumber {
-            return new BigNumber(2).toPower(this.width - 1).sub(1);
-        }
-
-        public getMinValue(): BigNumber {
-            return new BigNumber(2).toPower(this.width - 1).times(-1);
-        }
-
-        public getSignature(): string {
-            return `int${this.width}`;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    export class UInt extends Number {
-        static matcher = RegExp(
-            '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-        );
-
-        constructor(dataItem: DataItem) {
-            super(dataItem, UInt.matcher);
-        }
-
-        public getMaxValue(): BigNumber {
-            return new BigNumber(2).toPower(this.width).sub(1);
-        }
-
-        public getMinValue(): BigNumber {
-            return new BigNumber(0);
-        }
-
-        public getSignature(): string {
-            return `uint${this.width}`;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    export class Byte extends StaticDataType {
-        static matcher = RegExp(
-            '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
-        );
-
-        static DEFAULT_WIDTH = 1;
-        width: number = Byte.DEFAULT_WIDTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = Byte.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
-                this.width = parseInt(matches[2]);
-            } else {
-                this.width = Byte.DEFAULT_WIDTH;
-            }
-        }
-
-        public assignValue(value: string | Buffer) {
-            // Convert value into a buffer and do bounds checking
-            const valueBuf = ethUtil.toBuffer(value);
-            if (valueBuf.byteLength > this.width) {
-                throw new Error(
-                    `Tried to assign ${value} (${
-                    valueBuf.byteLength
-                    } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
-                );
-            } else if (value.length % 2 !== 0) {
-                throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-            }
-
-            // Store value as hex
-            const evmWordWidth = 32;
-            const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
-            const hexValue = ethUtil.bufferToHex(paddedValue);
-            this.assignHexValue(hexValue);
-        }
-
-        public getSignature(): string {
-            // Note that `byte` reduces to `bytes1`
-            return `bytes${this.width}`;
-        }
-
-        public isStatic(): boolean {
-            return true;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-    }
-
-    export class Bytes extends DynamicDataType {
-        static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = Bytes.UNDEFINED_LENGTH;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string | Buffer) {
-            if (typeof value === 'string' && !value.startsWith('0x')) {
-                throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
-            }
-            const valueBuf = ethUtil.toBuffer(value);
-            if (value.length % 2 !== 0) {
-                throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-            }
-
-            const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
-            const paddedBytesForValue = wordsForValue * 32;
-            const paddedValueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-            const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
-            const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
-            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
-
-            this.assignHexValue(encodedValue);
-        }
-
-        public getSignature(): string {
-            return 'bytes';
-        }
-
-        public isStatic(): boolean {
-            return false;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'bytes';
-        }
-    }
-
-    export class SolString extends DynamicDataType {
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(SolString.matchGrammar(dataItem.type)).to.be.true();
-        }
-
-        public assignValue(value: string) {
-            const wordsForValue = Math.ceil(value.length / 32);
-            const paddedBytesForValue = wordsForValue * 32;
-            const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-            const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
-            const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-            const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
-
-            this.assignHexValue(encodedValue);
-        }
-
-        public getSignature(): string {
-            return 'string';
-        }
-
-        public isStatic(): boolean {
-            return false;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'string';
-        }
-    }
-
-    export class SolArray extends DynamicDataType {
-        static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
-        static UNDEFINED_LENGTH = new BigNumber(-1);
-        length: BigNumber = SolArray.UNDEFINED_LENGTH;
-        type: string = '[undefined]';
-        isLengthDefined: boolean;
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            const matches = SolArray.matcher.exec(dataItem.type);
-            expect(matches).to.be.not.null();
-            console.log(JSON.stringify(matches));
-            if (matches === null || matches.length !== 3) {
-                throw new Error(`Could not parse array: ${dataItem.type}`);
-            } else if (matches[1] === undefined) {
-                throw new Error(`Could not parse array type: ${dataItem.type}`);
-            } else if (matches[2] === undefined) {
-                throw new Error(`Could not parse array length: ${dataItem.type}`);
-            }
-
-            // Check if length is undefined
-            if (matches[2] === '') {
-                this.type = matches[1];
-                this.length = SolArray.UNDEFINED_LENGTH;
-                this.isLengthDefined = false;
-                return;
-            }
-
-            // Parse out array type/length and construct children
-            this.isLengthDefined = true;
-            this.type = matches[1];
-            this.length = new BigNumber(matches[2], 10);
-            if (this.length.lessThan(0)) {
-                throw new Error(`Bad array length: ${JSON.stringify(this.length)}`);
-            }
-            this.constructChildren();
-        }
-
-        private constructChildren() {
-            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-                const childDataItem = {
-                    type: this.type,
-                    name: `${this.getDataItem().name}[${idx.toString(10)}]`,
-                } as DataItem;
-                const child = DataTypeFactory.create(childDataItem, this);
-                this.children.push(child);
-            }
-        }
-
-        // @TODO: HACKY -- shouldn't really have children for a 
-        public getChildren(): DataType[] {
-            if (this.isStatic()) {
-                return [];
-            } else {
-                return this.children;
-            }
-        }
-
-        public assignValue(value: any[]) {
-            // Sanity check length
-            const valueLength = new BigNumber(value.length);
-            if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
-                throw new Error(
-                    `Expected array of length ${JSON.stringify(this.length)}, but got array of length ${JSON.stringify(
-                        valueLength,
-                    )}`,
-                );
-            }
-
-            // Assign length if not already set
-            if (this.length === SolArray.UNDEFINED_LENGTH) {
-                this.length = valueLength;
-                this.constructChildren();
-            }
-
-            // Assign values to children
-            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-                const idxNumber = idx.toNumber();
-                this.children[idxNumber].assignValue(value[idxNumber]);
-            }
-        }
-
-        private getHexValueDynamicArray(): string {
-            const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
-            const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
-            let valueBuf = lengthBuf;
-
-            const valueHex = ethUtil.bufferToHex(valueBuf);
-            return valueHex;
-        }
-
-        private getHexValueStaticArray(): string {
-            let valueBuf = new Buffer("");
-
-            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-                const idxNumber = idx.toNumber();
-                const childValueHex = this.children[idxNumber].getHexValue();
-                const childValueBuf = ethUtil.toBuffer(childValueHex);
-                valueBuf = Buffer.concat([valueBuf, childValueBuf]);
-
-                console.log(JSON.stringify(idx));
-            }
-
-            // Convert value buffer to hex
-            const valueHex = ethUtil.bufferToHex(valueBuf);
-            return valueHex;
-        }
-
-        public getHexValue(): string {
-            if (this.isLengthDefined) {
-                return this.getHexValueStaticArray();
-            } else {
-                return this.getHexValueDynamicArray();
-            }
-        }
-
-        public isStatic(): boolean {
-            return this.isLengthDefined;
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return this.matcher.test(type);
-        }
-
-        public getSignature(): string {
-            let type = this.type;
-            if (this.type === 'tuple') {
-                let tupleDataItem = {
-                    type: 'tuple',
-                    name: 'N/A',
-                } as DataItem;
-                const tupleComponents = this.getDataItem().components;
-                if (tupleComponents !== undefined) {
-                    tupleDataItem.components = tupleComponents;
-                }
-                const tuple = new Tuple(tupleDataItem);
-                type = tuple.getSignature();
-            }
-
-            if (this.length.equals(SolArray.UNDEFINED_LENGTH)) {
-                return `${type}[]`;
-            }
-            return `${type}[${this.length}]`;
-        }
-    }
-
-    export class Tuple extends DynamicDataType {
-        private length: BigNumber;
-        private childMap: { [key: string]: number };
-
-        constructor(dataItem: DataItem) {
-            super(dataItem);
-            expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
-            this.length = new BigNumber(0);
-            this.childMap = {};
-            if (dataItem.components !== undefined) {
-                this.constructChildren(dataItem.components);
-                this.length = new BigNumber(dataItem.components.length);
-            } else {
-                throw new Error('Components undefined');
-            }
-        }
-
-        private constructChildren(dataItems: DataItem[]) {
-            _.each(dataItems, (dataItem: DataItem) => {
-                const childDataItem = {
-                    type: dataItem.type,
-                    name: `${this.getDataItem().name}.${dataItem.name}`,
-                } as DataItem;
-                const child = DataTypeFactory.create(childDataItem, this);
-                this.childMap[dataItem.name] = this.children.length;
-                this.children.push(child);
-            });
-        }
-
-        private assignValueFromArray(value: any[]) {
-            // Sanity check length
-            const valueLength = new BigNumber(value.length);
-            if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
-                throw new Error(
-                    `Expected array of ${JSON.stringify(
-                        this.length,
-                    )} elements, but got array of length ${JSON.stringify(valueLength)}`,
-                );
-            }
-
-            // Assign values to children
-            for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-                const idxNumber = idx.toNumber();
-                this.children[idxNumber].assignValue(value[idxNumber]);
-            }
-        }
-
-        private assignValueFromObject(obj: object) {
-            let childMap = _.cloneDeep(this.childMap);
-            _.forOwn(obj, (value: any, key: string) => {
-                if (key in childMap === false) {
-                    throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
-                }
-                this.children[this.childMap[key]].assignValue(value);
-                delete childMap[key];
-            });
-
-            if (Object.keys(childMap).length !== 0) {
-                throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
-            }
-        }
-
-        public assignValue(value: any[] | object) {
-            if (value instanceof Array) {
-                this.assignValueFromArray(value);
-            } else if (typeof value === 'object') {
-                this.assignValueFromObject(value);
-            } else {
-                throw new Error(`Unexpected type for ${value}`);
-            }
-        }
-
-        public getHexValue(): string {
-            return '0x';
-        }
-
-        public getSignature(): string {
-            // Compute signature
-            let signature = `(`;
-            _.each(this.children, (child: DataType, i: number) => {
-                signature += child.getSignature();
-                if (i < this.children.length - 1) {
-                    signature += ',';
-                }
-            });
-            signature += ')';
-            return signature;
-        }
-
-        public isStatic(): boolean {
-            return false; // @TODO: True in every case or only when dynamic data?
-        }
-
-        public static matchGrammar(type: string): boolean {
-            return type === 'tuple';
-        }
-    }
-
-    /* TODO
-    class Fixed extends StaticDataType {}
-
-    class UFixed extends StaticDataType {}*/
-
-    export class Pointer extends StaticDataType {
-        destDataType: DynamicDataType;
-        parentDataType: DataType;
-
-        constructor(destDataType: DynamicDataType, parentDataType: DataType) {
-            const destDataItem = destDataType.getDataItem();
-            const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
-            super(dataItem);
-            this.destDataType = destDataType;
-            this.parentDataType = parentDataType;
-            this.children.push(destDataType);
-        }
-
-        /*
-        public assignValue(destDataType: DynamicDataType) {
-            this.destDataType = destDataType;
-        }*/
-
-        public assignValue(value: any) {
-            this.destDataType.assignValue(value);
-        }
-
-        public getHexValue(): string {
-            console.log(
-                '*'.repeat(40),
-                this.destDataType.getAbsoluteOffset().toString(16),
-                '^'.repeat(150),
-                this.parentDataType.getAbsoluteOffset().toString(16),
-            );
-
-            let offset = this.destDataType
-                .getAbsoluteOffset()
-                .minus(this.parentDataType.getAbsoluteOffset().plus(this.parentDataType.getSize()));
-            const hexBase = 16;
-            const evmWordWidth = 32;
-            const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${offset.toString(hexBase)}`), evmWordWidth);
-            const encodedValue = ethUtil.bufferToHex(valueBuf);
-            return encodedValue;
-        }
-
-        public getSignature(): string {
-            return this.destDataType.getSignature();
-        }
-
-        public isStatic(): boolean {
-            return true;
-        }
-
-        public encodeToCalldata(calldata: Calldata): void {
-            throw 2;
-        }
-    }
-
-    export class DataTypeFactory {
-        public static mapDataItemToDataType(dataItem: DataItem): DataType {
-            console.log(`Type: ${dataItem.type}`);
-
-            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-            if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
-            if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-            if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
-            if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
-            if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
-            if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
-            if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-            if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
-            if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
-            //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
-            //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
-
-            throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-        }
-
-        public static create(dataItem: DataItem, parentDataType: DataType): DataType {
-            const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
-            if (dataType.isStatic()) {
-                return dataType;
-            } else {
-                const pointer = new Pointer(dataType, parentDataType);
-                return pointer;
-            }
-
-            throw new Error(`Unrecognized instance type: '${dataType}'`);
-        }
-    }
-
-    class Queue<T> {
-        private store: T[] = [];
-        push(val: T) {
-            this.store.push(val);
-        }
-        pop(): T | undefined {
-            return this.store.shift();
-        }
-    }
-
-    export class Method extends DataType {
-        name: string;
-        params: DataType[];
-        private signature: string;
-        selector: string;
-
-        constructor(abi: MethodAbi) {
-            super({ type: 'method', name: abi.name });
-            this.name = abi.name;
-            this.params = [];
-
-            _.each(abi.inputs, (input: DataItem) => {
-                this.params.push(DataTypeFactory.create(input, this));
-            });
-
-            // Compute signature
-            this.signature = `${this.name}(`;
-            _.each(this.params, (param: DataType, i: number) => {
-                this.signature += param.getSignature();
-                if (i < this.params.length - 1) {
-                    this.signature += ',';
-                }
-            });
-            this.signature += ')';
-
-            // Compute selector
-            this.selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(this.signature).slice(0, 4)));
-
-            console.log(`--SIGNATURE--\n${this.signature}\n---------\n`);
-            console.log(`--SELECTOR--\n${this.selector}\n---------\n`);
-        }
-
-        public getSignature(): string {
-            return this.signature;
-        }
-
-        public assignValue(args: any[]) {
-            const calldata = new Calldata(this.selector, this.params.length);
-            const params = this.params;
-            const paramQueue = new Queue<DataType>();
-            _.each(params, (param: DataType, i: number) => {
-                try {
-                    param.assignValue(args[i]);
-                } catch (e) {
-                    console.log('Failed to assign to ', param.getDataItem().name);
-                    throw e;
-                }
-                param.bind(calldata, CalldataSection.PARAMS);
-                _.each(param.getChildren(), (child: DataType) => {
-                    paramQueue.push(child);
-                });
-            });
-
-            let param: DataType | undefined = undefined;
-            while ((param = paramQueue.pop()) !== undefined) {
-                param.bind(calldata, CalldataSection.DATA);
-                _.each(param.getChildren(), (child: DataType) => {
-                    paramQueue.push(child);
-                });
-            }
-
-            console.log(calldata);
-
-            this.assignHexValue(calldata.getHexValue());
-
-            //return calldata.getRaw();
-        }
-
-        public encode(args: any[]): string {
-            this.assignValue(args);
-            return this.getHexValue();
-        }
-
-        public isStatic(): boolean {
-            return true;
-        }
-
-        /*
-        encodeOptimized(args: any[]): string {
-            const calldata = new Memory();
-            // Assign values
-            optimizableParams : StaticDataType = [];
-            _.each(this.params, function(args: any[], i: number, param: DataType) {
-                param.assignValue(args[i]);
-                if (param instanceof DynamicDataType) {
-
-                }
-            });
-
-            // Find non-parameter leaves
-
-
-            return '';
-        } */
-
-        /*
-        decode(rawCalldata: string): any[] {
-            const calldata = new Calldata(this.name, this.params.length);
-            calldata.assignRaw(rawCalldata);
-            let args: any[];
-            let params = this.params;
-            _.each(params, function(args: any[], i: number, param: DataType) {
-                param.decodeFromCalldata(calldata);
-                args.push(param.getValue());
-            });
-
-            return args;
-        }*/
-    }
-}
-
 describe.only('ABI Encoder', () => {
     describe.only('Just a Greg, Eh', () => {
+
+
         it('Crazy ABI', async () => {
-            const method = new AbiEncoder.Method(crazyAbi);
+            const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)],
@@ -1405,20 +129,50 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);*/
         });
 
-        it.only('Static Array ABI', async () => {
-            const method = new AbiEncoder.Method(staticArrayAbi);
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+        it.only('Fixed Lenfgth Array / Dynamic Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
+            const args = [["Brave", "New", "World"]];
             const calldata = method.encode(args);
             console.log(calldata);
             console.log('*'.repeat(40));
             console.log(JSON.stringify(args));
+            const expectedCalldata =
+                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.only('Unfixed Length Array / Dynamic Members ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
+            const args = [["Brave", "New", "World"]];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.only('Unfixed Length Array / Static Members ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+            const calldata = method.encode(args);
+            const expectedCalldata = '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+
+        it.only('Fixed Length Array / Static Members ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+            const calldata = method.encode(args);
             const expectedCalldata =
                 '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
+
         it('Simple ABI 2', async () => {
-            const method = new AbiEncoder.Method(simpleAbi2);
+            const method = new AbiEncoder.Method(AbiSamples.simpleAbi2);
 
             const args = [
                 '0xaf', // e (bytes1)
@@ -1434,14 +188,14 @@ describe.only('ABI Encoder', () => {
         });
 
         it('Yessir', async () => {
-            const method = new AbiEncoder.Method(simpleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.simpleAbi);
             const calldata = method.encode([new BigNumber(5), 'five']);
             console.log(calldata);
             expect(true).to.be.true();
         });
 
         it('Array ABI', async () => {
-            const method = new AbiEncoder.Method(stringAbi);
+            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
             const calldata = method.encode([['five', 'six', 'seven']]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -1453,7 +207,7 @@ describe.only('ABI Encoder', () => {
         });
 
         it('Object ABI (Array input)', async () => {
-            const method = new AbiEncoder.Method(tupleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
             const calldata = method.encode([[new BigNumber(5), 'five']]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -1465,7 +219,7 @@ describe.only('ABI Encoder', () => {
         });
 
         it('Object ABI (Object input)', async () => {
-            const method = new AbiEncoder.Method(tupleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -1477,7 +231,7 @@ describe.only('ABI Encoder', () => {
         });
 
         it.skip('Object ABI (Object input - Missing Key)', async () => {
-            const method = new AbiEncoder.Method(tupleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5) }]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -1491,7 +245,7 @@ describe.only('ABI Encoder', () => {
         });
 
         it.skip('Object ABI (Object input - Too Many Keys)', async () => {
-            const method = new AbiEncoder.Method(tupleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five', unwantedKey: 14 }]);
             console.log(method.getSignature());
             console.log(method.selector);
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
new file mode 100644
index 000000000..2e7111504
--- /dev/null
+++ b/packages/order-utils/test/abi_samples.ts
@@ -0,0 +1,358 @@
+import { MethodAbi } from 'ethereum-types';
+
+export const simpleAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'uint256',
+        },
+        {
+            name: 'gregStr',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const stringAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const tupleAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const staticArrayAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const staticArrayDynamicMembersAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'string[3]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const dynamicArrayDynamicMembersAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'string[]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const dynamicArrayStaticMembersAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const crazyAbi = {
+    constant: false,
+    inputs: [
+        /*{
+            name: 'someUInt256',
+            type: 'uint256',
+        },
+        {
+            name: 'someInt256',
+            type: 'int256',
+        },
+        {
+            name: 'someInt32',
+            type: 'int32',
+        },
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },*/
+        /*{
+            name: 'someAddress',
+            type: 'address',
+        },
+        {
+            name: 'someBool',
+            type: 'bool',
+        },*/
+
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        },
+        {
+            name: 'someStaticArrayWithDynamicMembers',
+            type: 'string[2]',
+        },
+        {
+            name: 'someDynamicArrayWithDynamicMembers',
+            type: 'bytes[]',
+        },
+        {
+            name: 'some2DArray',
+            type: 'string[][]',
+        },
+        {
+            name: 'someTuple',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+        },
+        {
+            name: 'someTupleWithDynamicTypes',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                //{
+                //      name: 'someStrArray',
+                //     type: 'string[]',
+                /// },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        } /*,
+        {
+            name: 'someArrayOfTuplesWithDynamicTypes',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                {
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        },*/,
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const simpleAbi2 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const fillOrderAbi = {
+    constant: false,
+    inputs: [
+        {
+            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: 'order',
+            type: 'tuple',
+        },
+        {
+            name: 'takerAssetFillAmount',
+            type: 'uint256',
+        },
+        {
+            name: 'salt',
+            type: 'uint256',
+        },
+        {
+            name: 'orderSignature',
+            type: 'bytes',
+        },
+        {
+            name: 'takerSignature',
+            type: 'bytes',
+        },
+    ],
+    name: 'fillOrder',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
-- 
cgit v1.2.3


From e95aa617b6eb0e4b6bace7fbcf66de2658e314aa Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 10:49:19 -0800
Subject: All existing ABI tests passing

---
 packages/order-utils/test/abi_encoder.ts      | 18 +++++++++++++-----
 packages/order-utils/test/abi_encoder_test.ts | 13 ++++++++-----
 2 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
index 55b63b701..77cb89056 100644
--- a/packages/order-utils/test/abi_encoder.ts
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -74,6 +74,7 @@ class Memblock {
     }
 
     public get(): string {
+        console.log(`Unstripped = '${this.dataType.getHexValue()}' and Stripped = '${ethUtil.stripHexPrefix(this.dataType.getHexValue())}'`);
         return ethUtil.stripHexPrefix(this.dataType.getHexValue());
     }
 
@@ -472,6 +473,7 @@ export class Byte extends StaticDataType {
         const evmWordWidth = 32;
         const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
         const hexValue = ethUtil.bufferToHex(paddedValue);
+
         this.assignHexValue(hexValue);
     }
 
@@ -538,7 +540,9 @@ export class Bytes extends DynamicDataType {
     }
 
     public getBodySize(): BigNumber {
-        return new BigNumber(this.getHexValue().length);
+        const valueBuf = ethUtil.toBuffer(this.getHexValue());
+        const size = new BigNumber(valueBuf.byteLength);
+        return size;
     }
 
     public static matchGrammar(type: string): boolean {
@@ -576,7 +580,9 @@ export class SolString extends DynamicDataType {
     }
 
     public getBodySize(): BigNumber {
-        return new BigNumber(this.getHexValue().length);
+        const valueBuf = ethUtil.toBuffer(this.getHexValue());
+        const size = new BigNumber(valueBuf.byteLength);
+        return size;
     }
 
     public static matchGrammar(type: string): boolean {
@@ -1032,12 +1038,14 @@ export class Method extends DataType {
     }
 
     public getHexValue(): string {
-        let value = "";
+        let paramBufs: Buffer[] = [];
         _.each(this.params, (param: DataType) => {
-            value += param.getHexValue();
+            paramBufs.push(ethUtil.toBuffer(param.getHexValue()));
         });
 
-        return value;
+        const value = Buffer.concat(paramBufs);
+        const hexValue = ethUtil.bufferToHex(value);
+        return hexValue;
     }
 
     public encode(args: any[]): string {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 315537226..91a32bfbf 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -22,7 +22,7 @@ describe.only('ABI Encoder', () => {
     describe.only('Just a Greg, Eh', () => {
 
 
-        it('Crazy ABI', async () => {
+        it.skip('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
@@ -114,6 +114,9 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             console.log(method.getSignature());
 
+            const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
             /*
             const expectedCalldata =
                 '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
@@ -129,7 +132,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);*/
         });
 
-        it.only('Fixed Lenfgth Array / Dynamic Members', async () => {
+        it('Fixed Lenfgth Array / Dynamic Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
             const args = [["Brave", "New", "World"]];
             const calldata = method.encode(args);
@@ -141,7 +144,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Unfixed Length Array / Dynamic Members ABI', async () => {
+        it('Unfixed Length Array / Dynamic Members ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
             const args = [["Brave", "New", "World"]];
             const calldata = method.encode(args);
@@ -152,7 +155,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Unfixed Length Array / Static Members ABI', async () => {
+        it('Unfixed Length Array / Static Members ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
             const calldata = method.encode(args);
@@ -161,7 +164,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it.only('Fixed Length Array / Static Members ABI', async () => {
+        it('Fixed Length Array / Static Members ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
             const calldata = method.encode(args);
-- 
cgit v1.2.3


From 3bc45395cc0e1c5c483e7319967b6308122123bf Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 11:14:44 -0800
Subject: static vs dynamic tuple differentatiion

---
 packages/order-utils/test/abi_encoder.ts      | 30 +++++++++++++++------
 packages/order-utils/test/abi_encoder_test.ts | 34 ++++++++++++++++-------
 packages/order-utils/test/abi_samples.ts      | 39 ++++++++++++++++++++++++---
 3 files changed, 83 insertions(+), 20 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
index 77cb89056..853aac627 100644
--- a/packages/order-utils/test/abi_encoder.ts
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -770,12 +770,14 @@ export class SolArray extends DynamicDataType {
 export class Tuple extends DynamicDataType {
     private length: BigNumber;
     private childMap: { [key: string]: number };
+    private members: DataType[];
 
     constructor(dataItem: DataItem) {
         super(dataItem);
         expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
         this.length = new BigNumber(0);
         this.childMap = {};
+        this.members = [];
         if (dataItem.components !== undefined) {
             this.constructChildren(dataItem.components);
             this.length = new BigNumber(dataItem.components.length);
@@ -792,7 +794,11 @@ export class Tuple extends DynamicDataType {
             } as DataItem;
             const child = DataTypeFactory.create(childDataItem, this);
             this.childMap[dataItem.name] = this.children.length;
-            this.children.push(child);
+
+            if (child instanceof Pointer) {
+                this.children.push(child.getChildren()[0]);
+            }
+            this.members.push(child);
         });
     }
 
@@ -810,7 +816,7 @@ export class Tuple extends DynamicDataType {
         // Assign values to children
         for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
             const idxNumber = idx.toNumber();
-            this.children[idxNumber].assignValue(value[idxNumber]);
+            this.members[idxNumber].assignValue(value[idxNumber]);
         }
     }
 
@@ -820,7 +826,7 @@ export class Tuple extends DynamicDataType {
             if (key in childMap === false) {
                 throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
             }
-            this.children[this.childMap[key]].assignValue(value);
+            this.members[this.childMap[key]].assignValue(value);
             delete childMap[key];
         });
 
@@ -840,7 +846,14 @@ export class Tuple extends DynamicDataType {
     }
 
     public getHexValue(): string {
-        return '0x';
+        let paramBufs: Buffer[] = [];
+        _.each(this.members, (member: DataType) => {
+            paramBufs.push(ethUtil.toBuffer(member.getHexValue()));
+        });
+
+        const value = Buffer.concat(paramBufs);
+        const hexValue = ethUtil.bufferToHex(value);
+        return hexValue;
     }
 
     public getHeaderSize(): BigNumber {
@@ -856,9 +869,9 @@ export class Tuple extends DynamicDataType {
     public getSignature(): string {
         // Compute signature
         let signature = `(`;
-        _.each(this.children, (child: DataType, i: number) => {
-            signature += child.getSignature();
-            if (i < this.children.length - 1) {
+        _.each(this.members, (member: DataType, i: number) => {
+            signature += member.getSignature();
+            if (i < this.members.length - 1) {
                 signature += ',';
             }
         });
@@ -867,7 +880,8 @@ export class Tuple extends DynamicDataType {
     }
 
     public isStatic(): boolean {
-        return false; // @TODO: True in every case or only when dynamic data?
+        const isStaticTuple = this.children.length === 0;
+        return isStaticTuple; // @TODO: True in every case or only when dynamic data?
     }
 
     public static matchGrammar(type: string): boolean {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 91a32bfbf..070bfe7f6 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -36,7 +36,7 @@ describe.only('ABI Encoder', () => {
                 '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
                 '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
             ], // m
-            [
+            /*[
                 [
                     'some string',
                     'some another string',
@@ -49,7 +49,7 @@ describe.only('ABI Encoder', () => {
                     'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
                 ],
                 [],
-            ], // n
+            ],*/ // n
             [
                 new BigNumber(4037824789),
                 'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
@@ -114,7 +114,9 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             console.log(method.getSignature());
 
-            const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
+            const expectedCalldata = '0x76c14e63000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e728347239823742398472398472984724892749874897428472894723948749874984787432942374349234732984723984237489237489237489234723894728947894748937428947289473894274982374329874238947238947328947238943724982374982374289347239800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000272834732984732489237492387423987423984728947298432789423749823748923748927439820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
+
+            //const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
 
             /*
@@ -209,8 +211,21 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it('Object ABI (Array input)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
+        it.only('Static Tuple', async () => {
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
+            const calldata = method.encode([[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata = '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Dynamic Tuple (Array input)', async () => {
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
             const calldata = method.encode([[new BigNumber(5), 'five']]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -221,8 +236,9 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it('Object ABI (Object input)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
+        it('Dynamic Tuple (Object input)', async () => {
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -234,7 +250,7 @@ describe.only('ABI Encoder', () => {
         });
 
         it.skip('Object ABI (Object input - Missing Key)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5) }]);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -248,7 +264,7 @@ describe.only('ABI Encoder', () => {
         });
 
         it.skip('Object ABI (Object input - Too Many Keys)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.tupleAbi);
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five', unwantedKey: 14 }]);
             console.log(method.getSignature());
             console.log(method.selector);
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index 2e7111504..fb5cfbeb7 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -34,7 +34,7 @@ export const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
-export const tupleAbi = {
+export const dynamicTupleAbi = {
     constant: false,
     inputs: [
         {
@@ -59,6 +59,39 @@ export const tupleAbi = {
     type: 'function',
 } as MethodAbi;
 
+export const staticTupleAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint1',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint3',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someBool',
+                    type: 'bool',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const staticArrayAbi = {
     constant: false,
     inputs: [
@@ -171,10 +204,10 @@ export const crazyAbi = {
             name: 'someDynamicArrayWithDynamicMembers',
             type: 'bytes[]',
         },
-        {
+        /* {
             name: 'some2DArray',
             type: 'string[][]',
-        },
+        }, */
         {
             name: 'someTuple',
             type: 'tuple',
-- 
cgit v1.2.3


From 687e6ccdd37da7c35a3fafac43f0fdff03351c0c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 11:33:51 -0800
Subject: Got the crazy ABI working

---
 packages/order-utils/test/abi_encoder.ts      | 44 ++++++++++++++++++++++-----
 packages/order-utils/test/abi_encoder_test.ts |  4 +--
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
index 853aac627..ae573b39f 100644
--- a/packages/order-utils/test/abi_encoder.ts
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -89,6 +89,10 @@ class Memblock {
     public getSection(): CalldataSection {
         return this.location.calldataSection;
     }
+
+    public getName(): string {
+        return this.dataType.getDataItem().name;
+    }
 }
 
 interface BindList {
@@ -120,13 +124,18 @@ export class Calldata {
             throw `Rebind on ${dataType.getId()}`;
         }
         const memblock = new Memblock(dataType);
+
+        this.params.push(memblock);
+        memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
+
+        console.log(`Binding ${dataType.getDataItem().name} to PARAMS at ${this.currentParamOffset}`);
+        this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
+        console.log("CURRENT PARAM OFFSET -------- 0x", this.currentParamOffset.toString(16));
+
+        /*
         switch (section) {
             case CalldataSection.PARAMS:
-                this.params.push(memblock);
-                memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
-
-                console.log(`Binding ${dataType.getDataItem().name} to PARAMS at ${this.currentParamOffset}`);
-                this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
+                ;
                 break;
 
             case CalldataSection.DATA:
@@ -143,7 +152,7 @@ export class Calldata {
 
             default:
                 throw `Unrecognized calldata section: ${section}`;
-        }
+        }*/
 
         this.bindList[dataType.getId()] = memblock;
         dataType.rbind(memblock);
@@ -160,6 +169,26 @@ export class Calldata {
 
         return hexValue;
     }
+
+    public printAnnotated() {
+        let hexValue = `${this.selector}`;
+        console.log(hexValue);
+        let offset = new BigNumber(0);
+        _.each(this.params, (memblock: Memblock) => {
+            const offsetStr = `0x${offset.toString(16)}`;
+            const hexValue = memblock.get();
+            const annotation = memblock.getName();
+
+            console.log(`${offsetStr} ${hexValue} ${annotation}`);
+        });
+        _.each(this.data, (memblock: Memblock) => {
+            const offsetStr = `0x${offset.toString(16)}`;
+            const hexValue = memblock.get();
+            const annotation = memblock.getName();
+
+            console.log(`${offsetStr} ${hexValue} ${annotation}`);
+        });
+    }
 }
 
 export abstract class DataType {
@@ -793,7 +822,7 @@ export class Tuple extends DynamicDataType {
                 name: `${this.getDataItem().name}.${dataItem.name}`,
             } as DataItem;
             const child = DataTypeFactory.create(childDataItem, this);
-            this.childMap[dataItem.name] = this.children.length;
+            this.childMap[dataItem.name] = this.members.length;
 
             if (child instanceof Pointer) {
                 this.children.push(child.getChildren()[0]);
@@ -1065,6 +1094,7 @@ export class Method extends DataType {
     public encode(args: any[]): string {
         this.assignValue(args);
         const calldata = new Calldata(this.selector, this.params.length);
+        calldata.printAnnotated();
         this.bind(calldata, CalldataSection.PARAMS);
 
         return calldata.getHexValue();
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 070bfe7f6..553fac43e 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -22,7 +22,7 @@ describe.only('ABI Encoder', () => {
     describe.only('Just a Greg, Eh', () => {
 
 
-        it.skip('Crazy ABI', async () => {
+        it('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
@@ -211,7 +211,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Static Tuple', async () => {
+        it('Static Tuple', async () => {
             // This is dynamic because it has dynamic members
             const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
             const calldata = method.encode([[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]]);
-- 
cgit v1.2.3


From e59669c94937ec694d9e41c1a163a8a6f770fd32 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 12:47:30 -0800
Subject: multidimensional arrays with static type

---
 packages/order-utils/test/abi_encoder.ts      |  1 -
 packages/order-utils/test/abi_encoder_test.ts | 40 ++++++++++++
 packages/order-utils/test/abi_samples.ts      | 87 +++++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
index ae573b39f..f63dc804a 100644
--- a/packages/order-utils/test/abi_encoder.ts
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -690,7 +690,6 @@ export class SolArray extends DynamicDataType {
             this.elements.push(child);
             if (child instanceof Pointer) {
                 const pointsTo = child.getChildren()[0];
-                console.log(JSON.stringify(pointsTo));
                 this.children.push(pointsTo); // DataType pointing to
             }
         }
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 553fac43e..115580624 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -134,6 +134,46 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);*/
         });
 
+        it.only('Multidimensional Arrays / Static Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
+
+            // Eight 3-dimensional arrays of uint8[2][2][2]
+            let value = 0;
+            const args = [];
+            for (let i = 0; i < 8; ++i) {
+                args.push(
+                    [
+                        [
+                            [new BigNumber(++value), new BigNumber(++value)],
+                            [new BigNumber(++value), new BigNumber(++value)],
+                        ],
+                        [
+                            [new BigNumber(++value), new BigNumber(++value)],
+                            [new BigNumber(++value), new BigNumber(++value)],
+                        ]
+                    ]
+                );
+            }
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Fixed Lenfgth Array / Dynamic Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
+            const args = [["Brave", "New", "World"]];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            const expectedCalldata =
+                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
         it('Fixed Lenfgth Array / Dynamic Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
             const args = [["Brave", "New", "World"]];
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index fb5cfbeb7..cbbc5f8f3 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -34,6 +34,93 @@ export const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
+export const multiDimensionalArraysStaticTypeAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'a',
+            type: 'uint8[][][]',
+        },
+        {
+            name: 'b',
+            type: 'uint8[][][2]',
+        },
+        {
+            name: 'c',
+            type: 'uint8[][2][]',
+        },
+        {
+            name: 'd',
+            type: 'uint8[2][][]',
+        },
+        {
+            name: 'e',
+            type: 'uint8[][2][2]',
+        },
+        {
+            name: 'f',
+            type: 'uint8[2][2][]',
+        },
+        {
+            name: 'g',
+            type: 'uint8[2][][2]',
+        },
+        {
+            name: 'h',
+            type: 'uint8[2][2][2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multiDimensionalArraysDynamicTypeAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'a',
+            type: 'string[][][2]',
+        },
+        {
+            name: 'a',
+            type: 'string[][1][]',
+        },
+        {
+            name: 'a',
+            type: 'string[1][1][2]',
+        },
+        {
+            name: 'a',
+            type: 'string[][][]',
+        },
+        {
+            name: 'a',
+            type: 'uint[][][]',
+        },
+        {
+            name: 'b',
+            type: 'uint8[][2][]',
+        },
+        {
+            name: 'c',
+            type: 'uint8[1][2][]',
+        },
+
+        {
+            name: 'c',
+            type: 'uint8[1][2][2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const dynamicTupleAbi = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From 180d1ca63a45ca96df2c9f811075411ca495f693 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 13:09:03 -0800
Subject: multidimensional arrays with dynamic objects

---
 packages/order-utils/test/abi_encoder_test.ts | 30 +++++++++++++++++++++++++++
 packages/order-utils/test/abi_samples.ts      | 25 ++++------------------
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 115580624..4ba9bb611 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -160,6 +160,36 @@ describe.only('ABI Encoder', () => {
             console.log(method.getSignature());
             console.log(JSON.stringify(args));
             const expectedCalldata = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; expect(calldata).to.be.equal(expectedCalldata);
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.only('Multidimensional Arrays / Dynamic Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
+
+            // Eight 3-dimensional arrays of string[2][2][2]
+            let value = 0;
+            const args = [];
+            for (let i = 0; i < 4; ++i) {
+                args.push(
+                    [
+                        [
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                        ],
+                        [
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                        ]
+                    ]
+                );
+            }
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
         });
 
         it('Fixed Lenfgth Array / Dynamic Members', async () => {
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index cbbc5f8f3..0882b389a 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -80,38 +80,21 @@ export const multiDimensionalArraysStaticTypeAbi = {
 export const multiDimensionalArraysDynamicTypeAbi = {
     constant: false,
     inputs: [
-        {
-            name: 'a',
-            type: 'string[][][2]',
-        },
-        {
-            name: 'a',
-            type: 'string[][1][]',
-        },
-        {
-            name: 'a',
-            type: 'string[1][1][2]',
-        },
         {
             name: 'a',
             type: 'string[][][]',
         },
-        {
-            name: 'a',
-            type: 'uint[][][]',
-        },
         {
             name: 'b',
-            type: 'uint8[][2][]',
+            type: 'string[][][2]',
         },
         {
             name: 'c',
-            type: 'uint8[1][2][]',
+            type: 'string[][2][]',
         },
-
         {
-            name: 'c',
-            type: 'uint8[1][2][2]',
+            name: 'h',
+            type: 'string[2][2][2]',
         },
     ],
     name: 'simpleFunction',
-- 
cgit v1.2.3


From 8f61f6d0f9532e95fd32cbab8dd0344b42de2da7 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 13:41:58 -0800
Subject: Arrays of tuples

---
 packages/order-utils/test/abi_encoder.ts      |   7 ++
 packages/order-utils/test/abi_encoder_test.ts |  76 ++++++++++++-
 packages/order-utils/test/abi_samples.ts      | 150 ++++++++++++++++++++++++++
 3 files changed, 231 insertions(+), 2 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
index f63dc804a..83ecc2f9a 100644
--- a/packages/order-utils/test/abi_encoder.ts
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -686,6 +686,10 @@ export class SolArray extends DynamicDataType {
                 type: this.type,
                 name: `${this.getDataItem().name}[${idx.toString(10)}]`,
             } as DataItem;
+            const components = this.getDataItem().components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
             const child = DataTypeFactory.create(childDataItem, this);
             this.elements.push(child);
             if (child instanceof Pointer) {
@@ -706,6 +710,9 @@ export class SolArray extends DynamicDataType {
     }*/
 
     public assignValue(value: any[]) {
+        console.log('GREG'.repeat(15), JSON.stringify(value));
+
+
         // Sanity check length
         const valueLength = new BigNumber(value.length);
         if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 4ba9bb611..cea33112d 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -134,7 +134,79 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);*/
         });
 
-        it.only('Multidimensional Arrays / Static Members', async () => {
+        it('Array of Static Tuples (Array has defined length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Array of Static Tuples (Array has dynamic length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Array of Dynamic Tuples (Array has defined length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it('Multidimensional Arrays / Static Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
 
             // Eight 3-dimensional arrays of uint8[2][2][2]
@@ -163,7 +235,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Multidimensional Arrays / Dynamic Members', async () => {
+        it('Multidimensional Arrays / Dynamic Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
 
             // Eight 3-dimensional arrays of string[2][2][2]
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index 0882b389a..7939cbaeb 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -129,6 +129,156 @@ export const dynamicTupleAbi = {
     type: 'function',
 } as MethodAbi;
 
+export const arrayOfStaticTuplesWithDefinedLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[8]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfStaticTuplesWithDynamicLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfDynamicTuplesWithDefinedLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[8]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfDynamicTuplesWithUndefinedLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfDynamicTuplesAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multidimensionalArrayOfDynamicTuplesAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[][2][]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const staticTupleAbi = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From 8b91727364c205cd2bd44abdabd62c1044dd13d4 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 13:57:36 -0800
Subject: types with default widths

---
 packages/order-utils/test/abi_encoder.ts      | 22 +++++++----------
 packages/order-utils/test/abi_encoder_test.ts | 12 +++++++++
 packages/order-utils/test/abi_samples.ts      | 35 +++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
index 83ecc2f9a..bcd427dee 100644
--- a/packages/order-utils/test/abi_encoder.ts
+++ b/packages/order-utils/test/abi_encoder.ts
@@ -781,20 +781,16 @@ export class SolArray extends DynamicDataType {
     }
 
     public getSignature(): string {
-        let type = this.type;
-        if (this.type === 'tuple') {
-            let tupleDataItem = {
-                type: 'tuple',
-                name: 'N/A',
-            } as DataItem;
-            const tupleComponents = this.getDataItem().components;
-            if (tupleComponents !== undefined) {
-                tupleDataItem.components = tupleComponents;
-            }
-            const tuple = new Tuple(tupleDataItem);
-            type = tuple.getSignature();
+        let dataItem = {
+            type: this.type,
+            name: 'N/A',
+        } as DataItem;
+        const components = this.getDataItem().components;
+        if (components !== undefined) {
+            dataItem.components = components;
         }
-
+        const elementDataType = DataTypeFactory.mapDataItemToDataType(dataItem);
+        const type = elementDataType.getSignature();
         if (this.length.equals(SolArray.UNDEFINED_LENGTH)) {
             return `${type}[]`;
         }
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index cea33112d..ad43e70a3 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -134,6 +134,18 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);*/
         });
 
+        it.only('Types with default widths', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
+            const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
         it('Array of Static Tuples (Array has defined length)', async () => {
             const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
 
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index 7939cbaeb..921408724 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -34,6 +34,41 @@ export const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
+export const typesWithDefaultWidthsAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someUint',
+            type: 'uint',
+        },
+        {
+            name: 'someInt',
+            type: 'int',
+        },
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someUint',
+            type: 'uint[]',
+        },
+        {
+            name: 'someInt',
+            type: 'int[]',
+        },
+        {
+            name: 'someByte',
+            type: 'byte[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const multiDimensionalArraysStaticTypeAbi = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From 1ca23b35ab067ed59a5d19543ceec646272e77a3 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 8 Nov 2018 14:23:41 -0800
Subject: complex type tesst

---
 packages/order-utils/test/abi_encoder_test.ts | 134 +++++++++++---------------
 packages/order-utils/test/abi_samples.ts      |  40 +++++---
 2 files changed, 80 insertions(+), 94 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index ad43e70a3..c8a0642ea 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -19,24 +19,23 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
-    describe.only('Just a Greg, Eh', () => {
-
+    describe.only('ABI Tests at Method Level', () => {
 
         it('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)],
-            [
+            const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
+            const someStaticArrayWithDynamicMembers = [
                 'the little piping piper piped a piping pipper papper',
                 'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-            ], // l
-            [
+            ];
+            const someDynamicArrayWithDynamicMembers = [
                 '0x38745637834987324827439287423897238947239847',
                 '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
                 '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
-            ], // m
-            /*[
+            ];
+            const some2DArray = [
                 [
                     'some string',
                     'some another string',
@@ -49,64 +48,32 @@ describe.only('ABI Encoder', () => {
                     'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
                 ],
                 [],
-            ],*/ // n
-            [
-                new BigNumber(4037824789),
-                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-            ], // o
-            [
-                new BigNumber('239048320948320948230', 10),
-                'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
-                /*[
-                    [
-                        '23432423342',
-                        'skdjfhdsjkfdhsfkjsdhfjkdshfdsjkfhsdjkfhsdjkfhdsjkfhdsjfhsdfjdshjkfsdhf',
-                        'sdfsdfdfdffsdf',
-                    ],
-                    [],
-                    [],
-                    ['23ehsdjkfhsiufhwfuefhesfhauhesufheuifhsefushfsufehfeuif'],
-                ],*/
-                '0xf74848484848484848484848484848484848483847576879809433994458585848932091',
-                '0xe41d2489571d322189246dafa5ebde1f4699f498',
-            ], // p
-                /*[
-                    [
-                        new BigNumber('23904848320948230', 10),
-                        'akdhjasshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
-                        [
-                            [
-                                '234324342',
-                                'skdjfhdsjkfdhsfkjsjkfhsdjkfhsdjkfhdsjkfhdsjfhsdfjdshjkfsdhf',
-                                'sdffdfdffsdf',
-                            ],
-                            [],
-                            [],
-                            ['23ehsdjkfhsiufhwfuefsufheuifhsefushfsufehfeuif'],
-                        ],
-                        '0xf7484848484848484848484848484876879809433994458585848932091',
-                        '0xe41d2489571d322189246dafa6ebde1f4699f498',
-                    ],
-                    [
-                        new BigNumber('23904832094832030', 10),
-                        'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdkdhsajkdhsadjk',
-                        [
-                            [
-                                '2343342',
-                                'skdjfhdsjkfdhsfkjsdhfjkdshfdsjkfhsdjkfhsdjkfhdssjfhsdfjdshjkfsdhf',
-                                'sdfsdfdfdffsf',
-                            ],
-                            [],
-                            [],
-                            ['jkfhsiufhwfuefhesfhauhesufhefeuif'],
-                        ],
-                        '0xf7484848484848484848484848484848484848384757687980943091',
-                        '0xe41d2489571d322189246dafa5ebde1f469af498',
-                    ],
-                    [],
-                    [],
-                ],*/
             ];
+            const someTuple = {
+                someUint32: new BigNumber(4037824789),
+                someStr: 'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.'
+            };
+            const someTupleWithDynamicTypes = {
+                someUint: new BigNumber(4024789),
+                someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+                someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
+                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
+            };
+            const someTupleWithDynamicTypes2 = {
+                someUint: new BigNumber(9024789),
+                someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
+                someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
+                someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
+            };
+            const someTupleWithDynamicTypes3 = {
+                someUint: new BigNumber(1024789),
+                someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
+                someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
+                someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
+            };
+            const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
+
+            const args = [someStaticArray, someStaticArrayWithDynamicMembers, someDynamicArrayWithDynamicMembers, some2DArray, someTuple, someTupleWithDynamicTypes, someArrayOfTuplesWithDynamicTypes];
 
             const calldata = method.encode(args);
             console.log(calldata);
@@ -114,27 +81,36 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             console.log(method.getSignature());
 
-            const expectedCalldata = '0x76c14e63000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e728347239823742398472398472984724892749874897428472894723948749874984787432942374349234732984723984237489237489237489234723894728947894748937428947289473894274982374329874238947238947328947238943724982374982374289347239800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000272834732984732489237492387423987423984728947298432789423749823748923748927439820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
-
+            const expectedCalldata = '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
             //const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+        });
 
-            /*
-            const expectedCalldata =
-                '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);*/
-
-            /*const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
+        it('Crazy ABI #1', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
+            const args = [
+                new BigNumber(256745454),
+                new BigNumber(-256745454),
+                new BigNumber(434244),
+                '0x43',
+                '0x0001020304050607080911121314151617181920212223242526272829303132',
+                '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
+                'Little peter piper piped a piping pepper pot',
+                '0xe41d2489571d322189246dafa5ebde1f4699f498',
+                true
+            ];
 
+            const calldata = method.encode(args);
             console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);*/
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Types with default widths', async () => {
+
+        it('Types with default widths', async () => {
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
             const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
             const calldata = method.encode(args);
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index 921408724..82427986a 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -407,10 +407,10 @@ export const dynamicArrayStaticMembersAbi = {
     type: 'function',
 } as MethodAbi;
 
-export const crazyAbi = {
+export const crazyAbi1 = {
     constant: false,
     inputs: [
-        /*{
+        {
             name: 'someUInt256',
             type: 'uint256',
         },
@@ -437,16 +437,26 @@ export const crazyAbi = {
         {
             name: 'someString',
             type: 'string',
-        },*/
-        /*{
+        },
+        {
             name: 'someAddress',
             type: 'address',
         },
         {
             name: 'someBool',
             type: 'bool',
-        },*/
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
 
+export const crazyAbi = {
+    constant: false,
+    inputs: [
         {
             name: 'someStaticArray',
             type: 'uint8[3]',
@@ -459,10 +469,10 @@ export const crazyAbi = {
             name: 'someDynamicArrayWithDynamicMembers',
             type: 'bytes[]',
         },
-        /* {
+        {
             name: 'some2DArray',
             type: 'string[][]',
-        }, */
+        },
         {
             name: 'someTuple',
             type: 'tuple',
@@ -489,10 +499,10 @@ export const crazyAbi = {
                     name: 'someStr',
                     type: 'string',
                 },
-                //{
-                //      name: 'someStrArray',
-                //     type: 'string[]',
-                /// },
+                /*{
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },*/
                 {
                     name: 'someBytes',
                     type: 'bytes',
@@ -502,7 +512,7 @@ export const crazyAbi = {
                     type: 'address',
                 },
             ],
-        } /*,
+        },
         {
             name: 'someArrayOfTuplesWithDynamicTypes',
             type: 'tuple[]',
@@ -515,10 +525,10 @@ export const crazyAbi = {
                     name: 'someStr',
                     type: 'string',
                 },
-                {
+                /*{
                     name: 'someStrArray',
                     type: 'string[]',
-                },
+                },*/
                 {
                     name: 'someBytes',
                     type: 'bytes',
@@ -528,7 +538,7 @@ export const crazyAbi = {
                     type: 'address',
                 },
             ],
-        },*/,
+        }
     ],
     name: 'simpleFunction',
     outputs: [],
-- 
cgit v1.2.3


From 78498b7019e02a9b280cc1ffe9fafbf30bff24ec Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 16:21:31 -0800
Subject: Initial port -- wont compile yet

---
 packages/order-utils/test/abi/abi_encoder.ts    |   1 +
 packages/order-utils/test/abi/calldata.ts       | 177 ++++++++++
 packages/order-utils/test/abi/config.ts         |   4 +
 packages/order-utils/test/abi/data_type.ts      | 278 +++++++++++++++
 packages/order-utils/test/abi/evm_data_types.ts | 439 ++++++++++++++++++++++++
 5 files changed, 899 insertions(+)
 create mode 100644 packages/order-utils/test/abi/abi_encoder.ts
 create mode 100644 packages/order-utils/test/abi/calldata.ts
 create mode 100644 packages/order-utils/test/abi/config.ts
 create mode 100644 packages/order-utils/test/abi/data_type.ts
 create mode 100644 packages/order-utils/test/abi/evm_data_types.ts

diff --git a/packages/order-utils/test/abi/abi_encoder.ts b/packages/order-utils/test/abi/abi_encoder.ts
new file mode 100644
index 000000000..12755209a
--- /dev/null
+++ b/packages/order-utils/test/abi/abi_encoder.ts
@@ -0,0 +1 @@
+export * from './calldata_block';
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
new file mode 100644
index 000000000..dc0fcfb2b
--- /dev/null
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -0,0 +1,177 @@
+import ethUtil = require('ethereumjs-util');
+var _ = require('lodash');
+
+export abstract class CalldataBlock {
+    private name: string;
+    private signature: string;
+    private offsetInBytes: number;
+    private headerSizeInBytes: number;
+    private bodySizeInBytes: number;
+    private relocatable: boolean;
+
+    constructor(name: string, signature: string, offsetInBytes: number, headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
+        this.name = name;
+        this.signature = signature;
+        this.offsetInBytes = offsetInBytes;
+        this.headerSizeInBytes = headerSizeInBytes;
+        this.bodySizeInBytes = bodySizeInBytes;
+        this.relocatable = relocatable;
+    }
+
+    public getName(): string {
+        return this.name;
+    }
+
+    public getSignature(): string {
+        return this.signature;
+    }
+
+    public isRelocatable(): boolean {
+        return this.relocatable;
+    }
+
+    public getHeaderSizeInBytes(): number {
+        return this.headerSizeInBytes;
+    }
+
+    public getBodySizeInBytes(): number {
+        return this.bodySizeInBytes;
+    }
+
+    public getSizeInBytes(): number {
+        return this.headerSizeInBytes + this.bodySizeInBytes;
+    }
+
+    public getOffsetInBytes(): number {
+        return this.offsetInBytes;
+    }
+
+    public abstract toHexString(): string;
+}
+
+export class PayloadCalldataBlock extends CalldataBlock {
+    private payload: Buffer;
+
+    constructor(name: string, signature: string, offsetInBytes: number, relocatable: boolean, payload: Buffer) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = payload.byteLength;
+        super(name, signature, offsetInBytes, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.payload = payload;
+    }
+
+    public toHexString(): string {
+        const payloadHex = ethUtil.bufferToHex(this.payload);
+        return payloadHex;
+    }
+}
+
+export class DependentCalldataBlock extends CalldataBlock {
+    public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private parent: CalldataBlock;
+    private dependency: CalldataBlock;
+
+    constructor(name: string, signature: string, offsetInBytes: number, relocatable: boolean, parent: CalldataBlock, dependency: CalldataBlock) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        super(name, signature, offsetInBytes, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.parent = parent;
+        this.dependency = dependency;
+    }
+
+    public toHexString(): string {
+        const dependencyOffset = this.dependency.getOffsetInBytes();
+        const parentOffset = this.parent.getOffsetInBytes();
+        const parentHeaderSize = this.parent.getHeaderSizeInBytes();
+        const pointer = dependencyOffset - parentOffset + parentHeaderSize;
+        const pointerBuf = new Buffer(`0x${pointer.toString(16)}`);
+        const evmWordWidthInBytes = 32;
+        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
+        const pointerHex = ethUtil.bufferToHex(pointerBufPadded);
+        return pointerHex;
+    }
+}
+
+export class MemberCalldataBlock extends CalldataBlock {
+    private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private header: Buffer | undefined;
+    private members: CalldataBlock[];
+
+    constructor(name: string, signature: string, offsetInBytes: number, relocatable: boolean, members: CalldataBlock[], header?: Buffer) {
+        const headerSizeInBytes = (header === undefined) ? 0 : header.byteLength;
+        let bodySizeInBytes = 0;
+        _.each(members, (member: Memblock) => {
+            bodySizeInBytes += member.getSizeInBytes();
+        });
+
+        super(name, signature, offsetInBytes, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.members = members;
+        this.header = header;
+    }
+
+    public toHexString(): string {
+        let valueBuffers: Buffer[] = [];
+        if (this.header !== undefined) valueBuffers.push(this.header);
+        _.each(this.members, (member: CalldataBlock) => {
+            const memberHexString = member.toHexString();
+            const memberBuf = ethUtil.toBuffer(memberHexString);
+            valueBuffers.push(memberBuf);
+        });
+        const combinedValueBufs = Buffer.concat(valueBuffers);
+        const combinedValuesAsHex = ethUtil.bufferToHex(combinedValueBufs);
+        return combinedValuesAsHex;
+    }
+}
+
+export class Calldata {
+    private selector: string;
+    private sizeInBytes: number;
+    private blocks: CalldataBlock[];
+
+    constructor() {
+        this.selector = '0x';
+        this.sizeInBytes = 0;
+        this.blocks = [];
+    }
+
+    public toHexString(): string {
+        let calldataString = `${this.selector}`;
+        _.each(this.blocks, (block: CalldataBlock) => {
+            const blockAsHexString = block.toHexString();
+            const blockAsHexWithoutPrefix = ethUtil.stripHexPrefix(blockAsHexString);
+            calldataString += blockAsHexWithoutPrefix;
+        });
+        return calldataString;
+    }
+
+    public getSelectorHex(): string {
+        return this.selector;
+    }
+
+    public getSizeInBytes(): number {
+        return this.sizeInBytes;
+    }
+
+    public toAnnotatedString(): string {
+        return "";
+    }
+
+    public pushBlock(block: CalldataBlock) {
+        this.blocks.push(block);
+        this.sizeInBytes += block.getSizeInBytes();
+    }
+
+    public setSelector(selector: string) {
+        // Ensure we have a 0x prefix
+        if (selector.startsWith('0x')) {
+            this.selector = selector;
+        } else {
+            this.selector = `$0x${selector}`;
+        }
+
+        // The selector must be 10 characters: '0x' followed by 4 bytes (two hex chars per byte)
+        if (this.selector.length !== 10) {
+            throw new Error(`Invalid selector '${this.selector}'`);
+        }
+        this.sizeInBytes += 8;
+    }
+}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/config.ts b/packages/order-utils/test/abi/config.ts
new file mode 100644
index 000000000..015cee59a
--- /dev/null
+++ b/packages/order-utils/test/abi/config.ts
@@ -0,0 +1,4 @@
+import { DataTypeFactory } from './data_type';
+import { EvmDataTypeFactoryImpl } from './evm_data_types';
+
+DataTypeFactory.setImpl(new EvmDataTypeFactoryImpl());
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
new file mode 100644
index 000000000..f74621085
--- /dev/null
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -0,0 +1,278 @@
+import { Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock } from "./calldata";
+import { MethodAbi, DataItem } from 'ethereum-types';
+import { BigNumber } from '@0x/utils';
+import ethUtil = require('ethereumjs-util');
+var _ = require('lodash');
+
+
+
+export abstract class DataType {
+    private dataItem: DataItem;
+
+    constructor(dataItem: DataItem) {
+        this.dataItem = dataItem;
+    }
+
+    public getDataItem(): DataItem {
+        return this.dataItem;
+    }
+
+    protected abstract createCalldataBlock(): CalldataBlock;
+    public abstract encode(value: any, calldata: Calldata): void;
+    public abstract getSignature(): string;
+    public abstract isStatic(): boolean;
+}
+
+export abstract class PayloadDataType extends DataType {
+    protected hasConstantSize: boolean;
+
+    public constructor(dataItem: DataItem, hasConstantSize: boolean) {
+        super(dataItem);
+        this.hasConstantSize = hasConstantSize;
+    }
+
+    protected generateCalldataBlock(payload: Buffer, calldata: Calldata): void {
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const offsetInBytes = calldata.getSizeInBytes();
+        const relocatable = false;
+        const block = new PayloadCalldataBlock(name, signature, offsetInBytes, relocatable, payload);
+        calldata.pushBlock(block);
+    }
+
+    public isStatic(): boolean {
+        // If a payload has a constant size then it's static
+        return this.hasConstantSize;
+    }
+}
+
+export abstract class DependentDataType extends DataType {
+    protected dependency: DataType;
+    protected parent: DataType;
+
+    public constructor(dataItem: DataItem, dependency: DataType, parent: DataType) {
+        super(dataItem);
+        this.dependency = dependency;
+        this.parent = parent;
+    }
+
+    protected generateCalldataBlock(offsetInBytes: number, calldata: Calldata): CalldataBlock {
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const relocatable = false;
+        const parentBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
+        const dependencyBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
+        const block = new DependentCalldataBlock(name, signature, offsetInBytes, relocatable, dependencyBlock, parentBlock);
+        calldata.pushBlock(block);
+    }
+
+    public encode(value: any, calldata: Calldata = new Calldata()): void {
+        const offsetInBytes = calldata.reserveSpace(DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES);
+        this.dependency.encode(value, calldata);
+        this.generateCalldataBlock(offsetInBytes, calldata);
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+}
+
+export interface MemberMap {
+    [key: string]: number;
+}
+
+export abstract class MemberDataType extends DataType {
+    private memberMap: MemberMap;
+    private members: DataType[];
+    private isArray: boolean;
+    protected arrayLength: number | undefined;
+
+
+    public constructor(dataItem: DataItem, isArray: boolean = false, arrayLength?: number) {
+        super(dataItem);
+
+        this.memberMap = {};
+        this.members = [];
+        this.isArray = isArray;
+        this.arrayLength = arrayLength;
+        if (isArray && arrayLength !== undefined) {
+            [this.members, this.memberMap] = MemberDataType.createMembersWithLength(arrayLength);
+        } else if (!isArray) {
+            [this.members, this.memberMap] = MemberDataType.createMembersWithKeys(dataItem);
+        }
+    }
+
+    private static createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+        // Sanity check
+        if (dataItem.components === undefined) {
+            throw new Error(`Expected components`);
+        }
+
+        let members: DataType[] = [];
+        let memberMap: MemberMap = {};
+        _.each(dataItem.components, (dataItem: DataItem) => {
+            const childDataItem = {
+                type: dataItem.type,
+                name: `${dataItem.name}.${dataItem.name}`,
+            } as DataItem;
+            const child = DataTypeFactory.create(childDataItem, this);
+            members.push(child);
+            memberMap[dataItem.name] = members.length;
+        });
+
+        return [members, memberMap];
+    }
+
+    private static createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        let members: DataType[] = [];
+        let memberMap: MemberMap = {};
+        const range = _.range(length);
+        _.each(range, (idx: number) => {
+            const childDataItem = {
+                type: this.type,
+                name: `${dataItem.name}[${idx.toString(10)}]`,
+            } as DataItem;
+            const components = dataItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = DataTypeFactory.create(childDataItem, this);
+            members.push(child);
+            memberMap[idx.toString(10)] = members.length;
+        });
+
+        return [members, memberMap];
+    }
+
+    protected encodeFromArray(value: any[], calldata: Calldata) {
+        // Sanity check length
+        const valueLength = new BigNumber(value.length);
+        if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
+            throw new Error(
+                `Expected array of ${JSON.stringify(
+                    this.length,
+                )} elements, but got array of length ${JSON.stringify(valueLength)}`,
+            );
+        }
+
+        // Assign values to children
+        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
+            const idxNumber = idx.toNumber();
+            this.members[idxNumber].assignValue(value[idxNumber]);
+        }
+    }
+
+    protected encodeFromObject(obj: object, calldata: Calldata) {
+        let childMap = _.cloneDeep(this.memberMap);
+        _.forOwn(obj, (value: any, key: string) => {
+            if (key in childMap === false) {
+                throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
+            }
+            this.members[this.childMap[key]].assignValue(value);
+            delete childMap[key];
+        });
+
+        if (Object.keys(childMap).length !== 0) {
+            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+        }
+    }
+
+    public encode(value: any[] | object, calldata = new Calldata()) {
+        if (value instanceof Array) {
+            this.encodeFromArray(value, calldata);
+        } else if (typeof value === 'object') {
+            this.encodeFromObject(value, encodeFromObject);
+        } else {
+            throw new Error(`Unexpected type for ${value}`);
+        }
+    }
+
+    protected generateCalldataBlock(offsetInBytes: number, calldata: Calldata): CalldataBlock {
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const relocatable = false;
+        const parentBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
+        const dependencyBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
+        const block = new DependentCalldataBlock(name, signature, offsetInBytes, relocatable, dependencyBlock, parentBlock);
+        calldata.pushBlock(block);
+    }
+
+    protected computeSignatureOfMembers(): string {
+        // Compute signature of members
+        let signature = `(`;
+        _.each(this.members, (member: DataType, i: number) => {
+            signature += member.getSignature();
+            if (i < this.members.length - 1) {
+                signature += ',';
+            }
+        });
+        signature += ')';
+        return signature;
+    }
+
+    public isStatic(): boolean {
+        /* For Tuple:
+                    const isStaticTuple = this.children.length === 0;
+                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
+
+           For Array:
+                if isLengthDefined = false then this is false
+
+                Otherwise if the first element is a Pointer then false
+        */
+
+        if (this.isArray && this.arrayLength === undefined) {
+            return true;
+        }
+
+        // Search for dependent members
+        const dependentMember = _.find(this.members, (member: DataType) => {
+            return (member instanceof DependentDataType);
+        });
+        const isStatic = (dependentMember === undefined); // static if we couldn't find a dependent member
+        return isStatic;
+    }
+}
+
+export interface DataTypeFactoryImpl {
+    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
+    mapDataItemToDataType: (dataItem: DataItem) => DataType;
+}
+
+export class DataTypeFactory {
+    private static instance: DataTypeFactory;
+    private provider: DataTypeFactoryImpl | undefined;
+
+    private constructor() { }
+
+    private static getInstance(): DataTypeFactory {
+        if (!DataTypeFactory.instance) {
+            DataTypeFactory.instance = new DataTypeFactory();
+        }
+        return DataTypeFactory.instance;
+    }
+
+    public static setImpl(provider: DataTypeFactoryImpl) {
+        const instance = DataTypeFactory.getInstance();
+        if (instance.provider !== undefined) {
+            throw new Error(`Tried to set implementation more than once`);
+        }
+        DataTypeFactory.getInstance().provider = provider;
+    }
+
+    public static create(dataItem: DataItem, parentDataType: DataType): DataType {
+        const instance = DataTypeFactory.getInstance();
+        if (instance.provider === undefined) {
+            throw new Error(`Tried to create before implementation is set`);
+        }
+        return instance.provider.create(dataItem, parentDataType);
+    }
+
+    public static mapDataItemToDataType(dataItem: DataItem): DataType {
+        const instance = DataTypeFactory.getInstance();
+        if (instance.provider === undefined) {
+            throw new Error(`Tried to create before implementation is set`);
+        }
+        return instance.provider.mapDataItemToDataType(dataItem);
+    }
+}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
new file mode 100644
index 000000000..4e42a992a
--- /dev/null
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -0,0 +1,439 @@
+import { DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+
+import { MethodAbi, DataItem } from 'ethereum-types';
+
+import ethUtil = require('ethereumjs-util');
+
+import { BigNumber } from '@0x/utils';
+
+export interface DataTypeStaticInterface {
+    matchGrammar: (type: string) => boolean;
+    encodeValue: (value: any) => Buffer;
+}
+
+export class Address extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Address.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Address.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'address';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'address';
+    }
+
+    public static encodeValue(value: boolean): Buffer {
+        const evmWordWidth = 32;
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
+        return encodedValueBuf;
+    }
+}
+
+export class Bool extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Bool.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bool.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'bool';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bool';
+    }
+
+    public static encodeValue(value: boolean): Buffer {
+        const evmWordWidth = 32;
+        const encodedValue = value === true ? '0x1' : '0x0';
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
+        return encodedValueBuf;
+    }
+}
+
+abstract class Number extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    static MAX_WIDTH: number = 256;
+    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
+    width: number = Number.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem, matcher: RegExp) {
+        super(dataItem, Number.SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = matcher.exec(dataItem.type);
+        if (matches === null) {
+            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
+        }
+        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
+            this.width = parseInt(matches[1]);
+        } else {
+            this.width = 256;
+        }
+    }
+
+    public static encodeValue(value: BigNumber): Buffer {
+        if (value.greaterThan(this.getMaxValue())) {
+            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+        } else if (value.lessThan(this.getMinValue())) {
+            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+        }
+
+        const hexBase = 16;
+        const evmWordWidth = 32;
+        let valueBuf: Buffer;
+        if (value.greaterThanOrEqualTo(0)) {
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
+        } else {
+            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
+            // Step 1/3: Convert value to positive binary string
+            const binBase = 2;
+            const valueBin = value.times(-1).toString(binBase);
+
+            // Step 2/3: Invert binary value
+            const bitsInEvmWord = 256;
+            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
+            _.each(valueBin, (bit: string) => {
+                invertedValueBin += bit === '1' ? '0' : '1';
+            });
+            const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+            // Step 3/3: Add 1 to inverted value
+            // The result is the two's-complement represent of the input value.
+            const negativeValue = invertedValue.plus(1);
+
+            // Convert the negated value to a hex string
+            valueBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
+                evmWordWidth,
+            );
+        }
+
+        return valueBuf;
+    }
+
+    public abstract getMaxValue(): BigNumber;
+    public abstract getMinValue(): BigNumber;
+}
+
+export class Int extends Number {
+    static matcher = RegExp(
+        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Int.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).times(-1);
+    }
+
+    public getSignature(): string {
+        return `int${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class UInt extends Number {
+    static matcher = RegExp(
+        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, UInt.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getSignature(): string {
+        return `uint${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Byte extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    static matcher = RegExp(
+        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+    );
+
+    static DEFAULT_WIDTH = 1;
+    width: number = Byte.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Byte.SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = Byte.matcher.exec(dataItem.type);
+        if (!Byte.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
+        }
+        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
+            this.width = parseInt(matches[2]);
+        } else {
+            this.width = Byte.DEFAULT_WIDTH;
+        }
+    }
+
+    public getSignature(): string {
+        // Note that `byte` reduces to `bytes1`
+        return `bytes${this.width}`;
+    }
+
+    public static encodeValue(value: string | Buffer): Buffer {
+        // Convert value into a buffer and do bounds checking
+        const valueBuf = ethUtil.toBuffer(value);
+        if (valueBuf.byteLength > this.width) {
+            throw new Error(
+                `Tried to assign ${value} (${
+                valueBuf.byteLength
+                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
+            );
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        // Store value as hex
+        const evmWordWidth = 32;
+        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
+        return paddedValue;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Bytes extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+    static UNDEFINED_LENGTH = new BigNumber(-1);
+    length: BigNumber = Bytes.UNDEFINED_LENGTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bytes.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
+        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
+        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
+        return encodedValueBuf;
+    }
+
+    public getSignature(): string {
+        return 'bytes';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bytes';
+    }
+}
+
+export class SolString extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+    constructor(dataItem: DataItem) {
+        super(dataItem, SolString.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!SolString.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
+        }
+    }
+
+    public static encodeValue(value: string): Buffer {
+        const wordsForValue = Math.ceil(value.length / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+        return encodedValueBuf;
+    }
+
+    public getSignature(): string {
+        return 'string';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'string';
+    }
+}
+
+export class Pointer extends DependentDataType {
+
+    constructor(destDataType: DataType, parentDataType: DataType) {
+        const destDataItem = destDataType.getDataItem();
+        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
+        super(dataItem, destDataType, parentDataType);
+    }
+
+    public getSignature(): string {
+        return this.dependency.getSignature();
+    }
+}
+
+export class Tuple extends MemberDataType {
+    private tupleSignature: string;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem);
+        if (!Tuple.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
+        }
+        this.tupleSignature = this.computeSignatureOfMembers();
+    }
+
+    public getSignature(): string {
+        return this.tupleSignature;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'tuple';
+    }
+}
+
+export class SolArray extends MemberDataType {
+    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    private arraySignature: string;
+    private elementType: string;
+
+    constructor(dataItem: DataItem) {
+        // Sanity check
+        const matches = SolArray.matcher.exec(dataItem.type);
+        if (matches === null || matches.length !== 3) {
+            throw new Error(`Could not parse array: ${dataItem.type}`);
+        } else if (matches[1] === undefined) {
+            throw new Error(`Could not parse array type: ${dataItem.type}`);
+        } else if (matches[2] === undefined) {
+            throw new Error(`Could not parse array length: ${dataItem.type}`);
+        }
+
+        const isArray = true;
+        const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
+        super(dataItem, isArray, arrayLength);
+        this.elementType = matches[1];
+        this.arraySignature = this.computeSignature();
+    }
+
+    private computeSignature(): string {
+        let dataItem = {
+            type: this.elementType,
+            name: 'N/A',
+        } as DataItem;
+        const components = this.getDataItem().components;
+        if (components !== undefined) {
+            dataItem.components = components;
+        }
+        const elementDataType = DataTypeFactory.mapDataItemToDataType(dataItem);
+        const type = elementDataType.getSignature();
+        if (this.arrayLength === undefined) {
+            return `${type}[]`;
+        } else {
+            return `${type}[${this.arrayLength}]`;
+        }
+    }
+
+    public getSignature(): string {
+        return this.arraySignature;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Method extends MemberDataType {
+    private methodSignature: string;
+    private methodSelector: string;
+
+    constructor(abi: MethodAbi) {
+        super({ type: 'method', name: abi.name });
+        this.methodSignature = this.computeSignature();
+        this.methodSelector = this.computeSelector();
+    }
+
+    private computeSignature(): string {
+        const memberSignature = this.computeSignatureOfMembers();
+        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
+        return methodSignature;
+    }
+
+    private computeSelector(): string {
+        const signature = this.computeSignature();
+        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(0, 4)));
+        return selector;
+    }
+
+    public getSignature(): string {
+        return this.methodSignature;
+    }
+
+    public getSelector(): string {
+        return this.methodSelector;
+    }
+}
+
+export class EvmDataTypeFactoryImpl implements DataTypeFactoryImpl {
+
+    public mapDataItemToDataType(dataItem: DataItem): DataType {
+        console.log(`Type: ${dataItem.type}`);
+
+        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
+        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
+        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
+        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
+        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
+        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
+        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
+        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
+        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
+        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
+
+        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+    }
+
+    public create(dataItem: DataItem, parentDataType: DataType): DataType {
+        const dataType = this.mapDataItemToDataType(dataItem);
+        if (dataType.isStatic()) {
+            return dataType;
+        }
+
+        const pointer = new Pointer(dataType, parentDataType);
+        return pointer;
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3


From 2802aed79cac4e73e64e1f33e328bcd05a4daf8b Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 18:10:58 -0800
Subject: refactored implementation done but not tested

---
 packages/order-utils/test/abi/calldata.ts       | 140 +++++++++++++++++-------
 packages/order-utils/test/abi/data_type.ts      |  98 +++++++++--------
 packages/order-utils/test/abi/evm_data_types.ts |  17 ++-
 3 files changed, 167 insertions(+), 88 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index dc0fcfb2b..725bdce62 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -9,15 +9,23 @@ export abstract class CalldataBlock {
     private bodySizeInBytes: number;
     private relocatable: boolean;
 
-    constructor(name: string, signature: string, offsetInBytes: number, headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
+    constructor(name: string, signature: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
         this.name = name;
         this.signature = signature;
-        this.offsetInBytes = offsetInBytes;
+        this.offsetInBytes = 0;
         this.headerSizeInBytes = headerSizeInBytes;
         this.bodySizeInBytes = bodySizeInBytes;
         this.relocatable = relocatable;
     }
 
+    protected setHeaderSize(headerSizeInBytes: number) {
+        this.headerSizeInBytes = headerSizeInBytes;
+    }
+
+    protected setBodySize(bodySizeInBytes: number) {
+        this.bodySizeInBytes = bodySizeInBytes;
+    }
+
     public getName(): string {
         return this.name;
     }
@@ -46,22 +54,25 @@ export abstract class CalldataBlock {
         return this.offsetInBytes;
     }
 
-    public abstract toHexString(): string;
+    public setOffset(offsetInBytes: number) {
+        this.offsetInBytes = offsetInBytes;
+    }
+
+    public abstract toBuffer(): Buffer;
 }
 
 export class PayloadCalldataBlock extends CalldataBlock {
     private payload: Buffer;
 
-    constructor(name: string, signature: string, offsetInBytes: number, relocatable: boolean, payload: Buffer) {
+    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = payload.byteLength;
-        super(name, signature, offsetInBytes, headerSizeInBytes, bodySizeInBytes, relocatable);
+        super(name, signature, /*offsetInBytes,*/ headerSizeInBytes, bodySizeInBytes, relocatable);
         this.payload = payload;
     }
 
-    public toHexString(): string {
-        const payloadHex = ethUtil.bufferToHex(this.payload);
-        return payloadHex;
+    public toBuffer(): Buffer {
+        return this.payload;
     }
 }
 
@@ -70,15 +81,15 @@ export class DependentCalldataBlock extends CalldataBlock {
     private parent: CalldataBlock;
     private dependency: CalldataBlock;
 
-    constructor(name: string, signature: string, offsetInBytes: number, relocatable: boolean, parent: CalldataBlock, dependency: CalldataBlock) {
+    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, parent: CalldataBlock, dependency: CalldataBlock) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, offsetInBytes, headerSizeInBytes, bodySizeInBytes, relocatable);
+        super(name, signature, /*offsetInBytes,*/ headerSizeInBytes, bodySizeInBytes, relocatable);
         this.parent = parent;
         this.dependency = dependency;
     }
 
-    public toHexString(): string {
+    public toBuffer(): Buffer {
         const dependencyOffset = this.dependency.getOffsetInBytes();
         const parentOffset = this.parent.getOffsetInBytes();
         const parentHeaderSize = this.parent.getHeaderSizeInBytes();
@@ -86,8 +97,11 @@ export class DependentCalldataBlock extends CalldataBlock {
         const pointerBuf = new Buffer(`0x${pointer.toString(16)}`);
         const evmWordWidthInBytes = 32;
         const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
-        const pointerHex = ethUtil.bufferToHex(pointerBufPadded);
-        return pointerHex;
+        return pointerBufPadded;
+    }
+
+    public getDependency(): CalldataBlock {
+        return this.dependency;
     }
 }
 
@@ -96,51 +110,97 @@ export class MemberCalldataBlock extends CalldataBlock {
     private header: Buffer | undefined;
     private members: CalldataBlock[];
 
-    constructor(name: string, signature: string, offsetInBytes: number, relocatable: boolean, members: CalldataBlock[], header?: Buffer) {
-        const headerSizeInBytes = (header === undefined) ? 0 : header.byteLength;
+    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean) {
+        super(name, signature, /*offsetInBytes,*/ 0, 0, relocatable);
+        this.members = [];
+        this.header = undefined;
+    }
+
+    public setMembers(members: CalldataBlock[]) {
         let bodySizeInBytes = 0;
-        _.each(members, (member: Memblock) => {
+        _.each(members, (member: CalldataBlock) => {
             bodySizeInBytes += member.getSizeInBytes();
         });
-
-        super(name, signature, offsetInBytes, headerSizeInBytes, bodySizeInBytes, relocatable);
         this.members = members;
+        this.setBodySize(bodySizeInBytes);
+    }
+
+    public setHeader(header: Buffer) {
+        this.setHeaderSize(header.byteLength);
         this.header = header;
     }
 
-    public toHexString(): string {
-        let valueBuffers: Buffer[] = [];
-        if (this.header !== undefined) valueBuffers.push(this.header);
-        _.each(this.members, (member: CalldataBlock) => {
-            const memberHexString = member.toHexString();
-            const memberBuf = ethUtil.toBuffer(memberHexString);
-            valueBuffers.push(memberBuf);
-        });
-        const combinedValueBufs = Buffer.concat(valueBuffers);
-        const combinedValuesAsHex = ethUtil.bufferToHex(combinedValueBufs);
-        return combinedValuesAsHex;
+    public toBuffer(): Buffer {
+        if (this.header !== undefined) return this.header;
+        return new Buffer('');
+    }
+
+    public getMembers(): CalldataBlock[] {
+        return this.members;
+    }
+}
+
+class Queue<T> {
+    private store: T[] = [];
+    push(val: T) {
+        this.store.push(val);
+    }
+    pop(): T | undefined {
+        return this.store.shift();
     }
 }
 
 export class Calldata {
     private selector: string;
     private sizeInBytes: number;
-    private blocks: CalldataBlock[];
+    private root: CalldataBlock | undefined;
 
     constructor() {
         this.selector = '0x';
         this.sizeInBytes = 0;
-        this.blocks = [];
+        this.root = undefined;
     }
 
     public toHexString(): string {
-        let calldataString = `${this.selector}`;
-        _.each(this.blocks, (block: CalldataBlock) => {
-            const blockAsHexString = block.toHexString();
-            const blockAsHexWithoutPrefix = ethUtil.stripHexPrefix(blockAsHexString);
-            calldataString += blockAsHexWithoutPrefix;
-        });
-        return calldataString;
+        let selectorBuffer = ethUtil.toBuffer(this.selector);
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const blockQueue = new Queue<CalldataBlock>();
+        blockQueue.push(this.root);
+
+        // Assign locations in breadth-first manner
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        while ((block = blockQueue.pop()) !== undefined) {
+            block.setOffset(offset);
+            if (block instanceof DependentCalldataBlock) {
+                blockQueue.push(block.getDependency());
+            } else if (block instanceof MemberCalldataBlock) {
+                _.each(block.getMembers(), (member: CalldataBlock) => {
+                    blockQueue.push(member);
+                });
+            }
+        }
+
+        // Fetch values using same technique
+        const valueBufs: Buffer[] = [selectorBuffer];
+        while ((block = blockQueue.pop()) !== undefined) {
+            valueBufs.push(block.toBuffer());
+
+            if (block instanceof DependentCalldataBlock) {
+                blockQueue.push(block.getDependency());
+            } else if (block instanceof MemberCalldataBlock) {
+                _.each(block.getMembers(), (member: CalldataBlock) => {
+                    blockQueue.push(member);
+                });
+            }
+        }
+
+        const combinedBuffers = Buffer.concat(valueBufs);
+        const hexValue = ethUtil.bufferToHex(combinedBuffers);
+        return hexValue;
     }
 
     public getSelectorHex(): string {
@@ -155,8 +215,8 @@ export class Calldata {
         return "";
     }
 
-    public pushBlock(block: CalldataBlock) {
-        this.blocks.push(block);
+    public setRoot(block: CalldataBlock) {
+        this.root = block;
         this.sizeInBytes += block.getSizeInBytes();
     }
 
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index f74621085..1a4610f7c 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -1,4 +1,4 @@
-import { Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock } from "./calldata";
+import { Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
 import { MethodAbi, DataItem } from 'ethereum-types';
 import { BigNumber } from '@0x/utils';
 import ethUtil = require('ethereumjs-util');
@@ -17,7 +17,7 @@ export abstract class DataType {
         return this.dataItem;
     }
 
-    protected abstract createCalldataBlock(): CalldataBlock;
+    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
     public abstract encode(value: any, calldata: Calldata): void;
     public abstract getSignature(): string;
     public abstract isStatic(): boolean;
@@ -31,19 +31,27 @@ export abstract class PayloadDataType extends DataType {
         this.hasConstantSize = hasConstantSize;
     }
 
-    protected generateCalldataBlock(payload: Buffer, calldata: Calldata): void {
+    public generateCalldataBlocks(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
+        const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
-        const offsetInBytes = calldata.getSizeInBytes();
+        // const offsetInBytes = calldata.getSizeInBytes();
         const relocatable = false;
-        const block = new PayloadCalldataBlock(name, signature, offsetInBytes, relocatable, payload);
-        calldata.pushBlock(block);
+        const block = new PayloadCalldataBlock(name, signature, /*offsetInBytes,*/ relocatable, encodedValue);
+        return block;
+    }
+
+    public encode(value: any, calldata: Calldata): void {
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block);
     }
 
     public isStatic(): boolean {
         // If a payload has a constant size then it's static
         return this.hasConstantSize;
     }
+
+    public abstract encodeValue(value: any): Buffer;
 }
 
 export abstract class DependentDataType extends DataType {
@@ -56,20 +64,21 @@ export abstract class DependentDataType extends DataType {
         this.parent = parent;
     }
 
-    protected generateCalldataBlock(offsetInBytes: number, calldata: Calldata): CalldataBlock {
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
+        if (parentBlock === undefined) {
+            throw new Error(`DependentDataType requires a parent block to generate its block`);
+        }
+        const dependencyBlock = this.dependency.generateCalldataBlock(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const relocatable = false;
-        const parentBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
-        const dependencyBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
-        const block = new DependentCalldataBlock(name, signature, offsetInBytes, relocatable, dependencyBlock, parentBlock);
-        calldata.pushBlock(block);
+        const block = new DependentCalldataBlock(name, signature, /*offsetInBytes,*/ relocatable, dependencyBlock, parentBlock);
+        return block;
     }
 
     public encode(value: any, calldata: Calldata = new Calldata()): void {
-        const offsetInBytes = calldata.reserveSpace(DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES);
-        this.dependency.encode(value, calldata);
-        this.generateCalldataBlock(offsetInBytes, calldata);
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block);
     }
 
     public isStatic(): boolean {
@@ -96,7 +105,7 @@ export abstract class MemberDataType extends DataType {
         this.isArray = isArray;
         this.arrayLength = arrayLength;
         if (isArray && arrayLength !== undefined) {
-            [this.members, this.memberMap] = MemberDataType.createMembersWithLength(arrayLength);
+            [this.members, this.memberMap] = MemberDataType.createMembersWithLength(dataItem, arrayLength);
         } else if (!isArray) {
             [this.members, this.memberMap] = MemberDataType.createMembersWithKeys(dataItem);
         }
@@ -129,7 +138,7 @@ export abstract class MemberDataType extends DataType {
         const range = _.range(length);
         _.each(range, (idx: number) => {
             const childDataItem = {
-                type: this.type,
+                type: dataItem.type,
                 name: `${dataItem.name}[${idx.toString(10)}]`,
             } as DataItem;
             const components = dataItem.components;
@@ -144,57 +153,60 @@ export abstract class MemberDataType extends DataType {
         return [members, memberMap];
     }
 
-    protected encodeFromArray(value: any[], calldata: Calldata) {
+    protected generateCalldataBlockFromArray(value: any[]): MemberCalldataBlock {
         // Sanity check length
-        const valueLength = new BigNumber(value.length);
-        if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
+        if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
             throw new Error(
                 `Expected array of ${JSON.stringify(
-                    this.length,
-                )} elements, but got array of length ${JSON.stringify(valueLength)}`,
+                    this.arrayLength,
+                )} elements, but got array of length ${JSON.stringify(value.length)}`,
             );
         }
 
-        // Assign values to children
-        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-            const idxNumber = idx.toNumber();
-            this.members[idxNumber].assignValue(value[idxNumber]);
+        let members = this.members;
+        if (this.arrayLength === undefined) {
+            [members,] = MemberDataType.createMembersWithLength(this.getDataItem(), value.length);
         }
+
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
+        const memberBlocks: CalldataBlock[] = [];
+        _.each(members, (member: DataType) => {
+            const block = member.generateCalldataBlock(value, methodBlock);
+            memberBlocks.push(block);
+        });
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
     }
 
-    protected encodeFromObject(obj: object, calldata: Calldata) {
+    protected generateCalldataBlockFromObject(obj: object): MemberCalldataBlock {
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
+        const memberBlocks: CalldataBlock[] = [];
         let childMap = _.cloneDeep(this.memberMap);
         _.forOwn(obj, (value: any, key: string) => {
             if (key in childMap === false) {
                 throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
             }
-            this.members[this.childMap[key]].assignValue(value);
+            const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
+            memberBlocks.push(block);
             delete childMap[key];
         });
 
         if (Object.keys(childMap).length !== 0) {
             throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
         }
+
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
     }
 
-    public encode(value: any[] | object, calldata = new Calldata()) {
-        if (value instanceof Array) {
-            this.encodeFromArray(value, calldata);
-        } else if (typeof value === 'object') {
-            this.encodeFromObject(value, encodeFromObject);
-        } else {
-            throw new Error(`Unexpected type for ${value}`);
-        }
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value) : this.generateCalldataBlockFromObject(value, calldata);
+        return block;
     }
 
-    protected generateCalldataBlock(offsetInBytes: number, calldata: Calldata): CalldataBlock {
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const relocatable = false;
-        const parentBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
-        const dependencyBlock = calldata.lookupBlockByName(this.parent.getDataItem().name);
-        const block = new DependentCalldataBlock(name, signature, offsetInBytes, relocatable, dependencyBlock, parentBlock);
-        calldata.pushBlock(block);
+    public encode(value: any, calldata: Calldata = new Calldata()): void {
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block);
     }
 
     protected computeSignatureOfMembers(): string {
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index 4e42a992a..bdbaf5b3c 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -4,6 +4,8 @@ import { MethodAbi, DataItem } from 'ethereum-types';
 
 import ethUtil = require('ethereumjs-util');
 
+import { Calldata } from './calldata';
+
 import { BigNumber } from '@0x/utils';
 
 export interface DataTypeStaticInterface {
@@ -29,7 +31,7 @@ export class Address extends PayloadDataType {
         return type === 'address';
     }
 
-    public static encodeValue(value: boolean): Buffer {
+    public encodeValue(value: boolean): Buffer {
         const evmWordWidth = 32;
         const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
         return encodedValueBuf;
@@ -54,7 +56,7 @@ export class Bool extends PayloadDataType {
         return type === 'bool';
     }
 
-    public static encodeValue(value: boolean): Buffer {
+    public encodeValue(value: boolean): Buffer {
         const evmWordWidth = 32;
         const encodedValue = value === true ? '0x1' : '0x0';
         const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
@@ -81,7 +83,7 @@ abstract class Number extends PayloadDataType {
         }
     }
 
-    public static encodeValue(value: BigNumber): Buffer {
+    public encodeValue(value: BigNumber): Buffer {
         if (value.greaterThan(this.getMaxValue())) {
             throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
         } else if (value.lessThan(this.getMinValue())) {
@@ -204,7 +206,7 @@ export class Byte extends PayloadDataType {
         return `bytes${this.width}`;
     }
 
-    public static encodeValue(value: string | Buffer): Buffer {
+    public encodeValue(value: string | Buffer): Buffer {
         // Convert value into a buffer and do bounds checking
         const valueBuf = ethUtil.toBuffer(value);
         if (valueBuf.byteLength > this.width) {
@@ -275,7 +277,7 @@ export class SolString extends PayloadDataType {
         }
     }
 
-    public static encodeValue(value: string): Buffer {
+    public encodeValue(value: string): Buffer {
         const wordsForValue = Math.ceil(value.length / 32);
         const paddedBytesForValue = wordsForValue * 32;
         const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
@@ -398,6 +400,11 @@ export class Method extends MemberDataType {
         return selector;
     }
 
+    public encode(value: any[] | object, calldata = new Calldata()) {
+        calldata.setSelector(this.methodSelector);
+        super.encode(value, calldata);
+    }
+
     public getSignature(): string {
         return this.methodSignature;
     }
-- 
cgit v1.2.3


From 1f7fbcf52ccc037c4c4bb49e629eecc83e5309e5 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 18:14:31 -0800
Subject: Should build? TBD!

---
 packages/order-utils/test/abi/abi_encoder.ts    | 5 ++++-
 packages/order-utils/test/abi/evm_data_types.ts | 3 ++-
 packages/order-utils/test/abi_encoder_test.ts   | 5 ++++-
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/packages/order-utils/test/abi/abi_encoder.ts b/packages/order-utils/test/abi/abi_encoder.ts
index 12755209a..ddcfb1fd1 100644
--- a/packages/order-utils/test/abi/abi_encoder.ts
+++ b/packages/order-utils/test/abi/abi_encoder.ts
@@ -1 +1,4 @@
-export * from './calldata_block';
\ No newline at end of file
+export * from './config';
+export * from './calldata';
+export * from './data_type';
+export * from './evm_data_types';
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index bdbaf5b3c..15fe4c9e3 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -400,9 +400,10 @@ export class Method extends MemberDataType {
         return selector;
     }
 
-    public encode(value: any[] | object, calldata = new Calldata()) {
+    public encode(value: any[] | object, calldata = new Calldata()): string {
         calldata.setSelector(this.methodSelector);
         super.encode(value, calldata);
+        return calldata.toHexString();
     }
 
     public getSignature(): string {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index c8a0642ea..f46a1812c 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -12,7 +12,10 @@ import { MethodAbi, DataItem } from 'ethereum-types';
 
 import { BigNumber } from '@0x/utils';
 import { assert } from '@0x/order-utils/src/assert';
-import * as AbiEncoder from './abi_encoder';
+//import * as AbiEncoder from './abi_encoder';
+
+import * as AbiEncoder from './abi/abi_encoder';
+
 import * as AbiSamples from './abi_samples';
 
 chaiSetup.configure();
-- 
cgit v1.2.3


From 0835cf0ea2bb3c2c18d2a5d44ec914e2945af1b0 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 18:18:52 -0800
Subject: Refactor Builds!

---
 packages/order-utils/test/abi/data_type.ts      |   14 +-
 packages/order-utils/test/abi/evm_data_types.ts |    8 +-
 packages/order-utils/test/abi_encoder.ts        | 1152 -----------------------
 packages/order-utils/test/abi_encoder_test.ts   |  466 ++++-----
 4 files changed, 247 insertions(+), 1393 deletions(-)
 delete mode 100644 packages/order-utils/test/abi_encoder.ts

diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 1a4610f7c..201eb89f9 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -31,7 +31,7 @@ export abstract class PayloadDataType extends DataType {
         this.hasConstantSize = hasConstantSize;
     }
 
-    public generateCalldataBlocks(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
@@ -105,13 +105,13 @@ export abstract class MemberDataType extends DataType {
         this.isArray = isArray;
         this.arrayLength = arrayLength;
         if (isArray && arrayLength !== undefined) {
-            [this.members, this.memberMap] = MemberDataType.createMembersWithLength(dataItem, arrayLength);
+            [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
         } else if (!isArray) {
-            [this.members, this.memberMap] = MemberDataType.createMembersWithKeys(dataItem);
+            [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
         }
     }
 
-    private static createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+    private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
         // Sanity check
         if (dataItem.components === undefined) {
             throw new Error(`Expected components`);
@@ -132,7 +132,7 @@ export abstract class MemberDataType extends DataType {
         return [members, memberMap];
     }
 
-    private static createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+    private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
         let members: DataType[] = [];
         let memberMap: MemberMap = {};
         const range = _.range(length);
@@ -165,7 +165,7 @@ export abstract class MemberDataType extends DataType {
 
         let members = this.members;
         if (this.arrayLength === undefined) {
-            [members,] = MemberDataType.createMembersWithLength(this.getDataItem(), value.length);
+            [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
         }
 
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
@@ -200,7 +200,7 @@ export abstract class MemberDataType extends DataType {
     }
 
     public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value) : this.generateCalldataBlockFromObject(value, calldata);
+        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value) : this.generateCalldataBlockFromObject(value);
         return block;
     }
 
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index 15fe4c9e3..4dffedb8d 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -8,6 +8,8 @@ import { Calldata } from './calldata';
 
 import { BigNumber } from '@0x/utils';
 
+var _ = require('lodash');
+
 export interface DataTypeStaticInterface {
     matchGrammar: (type: string) => boolean;
     encodeValue: (value: any) => Buffer;
@@ -382,10 +384,14 @@ export class Method extends MemberDataType {
     private methodSignature: string;
     private methodSelector: string;
 
+    // TMP
+    public selector: string;
+
     constructor(abi: MethodAbi) {
         super({ type: 'method', name: abi.name });
         this.methodSignature = this.computeSignature();
-        this.methodSelector = this.computeSelector();
+        this.selector = this.methodSelector = this.computeSelector();
+
     }
 
     private computeSignature(): string {
diff --git a/packages/order-utils/test/abi_encoder.ts b/packages/order-utils/test/abi_encoder.ts
deleted file mode 100644
index bcd427dee..000000000
--- a/packages/order-utils/test/abi_encoder.ts
+++ /dev/null
@@ -1,1152 +0,0 @@
-
-import * as chai from 'chai';
-import 'mocha';
-import ethUtil = require('ethereumjs-util');
-
-var _ = require('lodash');
-
-import { chaiSetup } from './utils/chai_setup';
-
-import { MethodAbi, DataItem } from 'ethereum-types';
-
-import { BigNumber } from '@0x/utils';
-import { bigNumberify } from 'ethers/utils';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-
-class Word {
-    private value: string;
-
-    constructor(value?: string) {
-        if (value === undefined) {
-            this.value = '';
-        } else {
-            this.value = value;
-        }
-    }
-
-    public set(value: string) {
-        if (value.length !== 64) {
-            throw `Tried to create word that is not 32 bytes: ${value}`;
-        }
-
-        this.value = value;
-    }
-
-    public get(): string {
-        return this.value;
-    }
-
-    public getAsHex(): string {
-        return `0x${this.value}`;
-    }
-}
-
-export enum CalldataSection {
-    NONE,
-    PARAMS,
-    DATA,
-}
-
-class Memblock {
-    private dataType: DataType;
-    private location: { calldataSection: CalldataSection; sectionOffset: BigNumber; offset: BigNumber };
-
-    constructor(dataType: DataType) {
-        this.dataType = dataType;
-        this.location = {
-            calldataSection: CalldataSection.NONE,
-            sectionOffset: new BigNumber(0),
-            offset: new BigNumber(0),
-        };
-    }
-
-    public getSize(): BigNumber {
-        return new BigNumber(ethUtil.toBuffer(this.dataType.getHexValue()).byteLength);
-    }
-
-    public assignLocation(calldataSection: CalldataSection, sectionOffset: BigNumber, offset: BigNumber) {
-        this.location.calldataSection = calldataSection;
-        this.location.sectionOffset = sectionOffset;
-        this.location.offset = offset;
-    }
-
-    public get(): string {
-        console.log(`Unstripped = '${this.dataType.getHexValue()}' and Stripped = '${ethUtil.stripHexPrefix(this.dataType.getHexValue())}'`);
-        return ethUtil.stripHexPrefix(this.dataType.getHexValue());
-    }
-
-    public getOffset(): BigNumber {
-        return this.location.offset;
-    }
-
-    public getAbsoluteOffset(): BigNumber {
-        return this.location.sectionOffset.plus(this.location.offset);
-    }
-
-    public getSection(): CalldataSection {
-        return this.location.calldataSection;
-    }
-
-    public getName(): string {
-        return this.dataType.getDataItem().name;
-    }
-}
-
-interface BindList {
-    [key: string]: Memblock;
-}
-
-export class Calldata {
-    private selector: string;
-    private params: Memblock[];
-    private data: Memblock[];
-    private dataOffset: BigNumber;
-    private currentDataOffset: BigNumber;
-    private currentParamOffset: BigNumber;
-    private bindList: BindList;
-
-    constructor(selector: string, nParams: number) {
-        this.selector = selector;
-        this.params = [];
-        this.data = [];
-        const evmWordSize = 32;
-        this.dataOffset = new BigNumber(nParams).times(evmWordSize);
-        this.currentDataOffset = new BigNumber(0);
-        this.currentParamOffset = new BigNumber(0);
-        this.bindList = {};
-    }
-
-    public bind(dataType: DataType, section: CalldataSection) {
-        if (dataType.getId() in this.bindList) {
-            throw `Rebind on ${dataType.getId()}`;
-        }
-        const memblock = new Memblock(dataType);
-
-        this.params.push(memblock);
-        memblock.assignLocation(section, new BigNumber(0), this.currentParamOffset);
-
-        console.log(`Binding ${dataType.getDataItem().name} to PARAMS at ${this.currentParamOffset}`);
-        this.currentParamOffset = this.currentParamOffset.plus(memblock.getSize());
-        console.log("CURRENT PARAM OFFSET -------- 0x", this.currentParamOffset.toString(16));
-
-        /*
-        switch (section) {
-            case CalldataSection.PARAMS:
-                ;
-                break;
-
-            case CalldataSection.DATA:
-                this.data.push(memblock);
-                memblock.assignLocation(section, this.dataOffset, this.currentDataOffset);
-
-                console.log(
-                    `Binding ${dataType.getDataItem().name} to DATA at ${memblock
-                        .getAbsoluteOffset()
-                        .toString(16)}`,
-                );
-                this.currentDataOffset = this.currentDataOffset.plus(memblock.getSize());
-                break;
-
-            default:
-                throw `Unrecognized calldata section: ${section}`;
-        }*/
-
-        this.bindList[dataType.getId()] = memblock;
-        dataType.rbind(memblock);
-    }
-
-    public getHexValue(): string {
-        let hexValue = `${this.selector}`;
-        _.each(this.params, (memblock: Memblock) => {
-            hexValue += memblock.get();
-        });
-        _.each(this.data, (memblock: Memblock) => {
-            hexValue += memblock.get();
-        });
-
-        return hexValue;
-    }
-
-    public printAnnotated() {
-        let hexValue = `${this.selector}`;
-        console.log(hexValue);
-        let offset = new BigNumber(0);
-        _.each(this.params, (memblock: Memblock) => {
-            const offsetStr = `0x${offset.toString(16)}`;
-            const hexValue = memblock.get();
-            const annotation = memblock.getName();
-
-            console.log(`${offsetStr} ${hexValue} ${annotation}`);
-        });
-        _.each(this.data, (memblock: Memblock) => {
-            const offsetStr = `0x${offset.toString(16)}`;
-            const hexValue = memblock.get();
-            const annotation = memblock.getName();
-
-            console.log(`${offsetStr} ${hexValue} ${annotation}`);
-        });
-    }
-}
-
-export abstract class DataType {
-    private dataItem: DataItem;
-    private hexValue: string;
-    protected memblock: Memblock | undefined;
-    protected children: DataType[];
-
-    constructor(dataItem: DataItem) {
-        this.dataItem = dataItem;
-        this.hexValue = '0x';
-        this.memblock = undefined;
-        this.children = [];
-    }
-
-    protected assignHexValue(hexValue: string) {
-        this.hexValue = hexValue;
-    }
-
-    public getHexValue(): string {
-        return this.hexValue;
-    }
-
-    public getDataItem(): DataItem {
-        return this.dataItem;
-    }
-
-    public rbind(memblock: Memblock) {
-        this.memblock = memblock;
-    }
-
-    public bind(calldata: Calldata, section: CalldataSection) {
-        calldata.bind(this, section);
-        _.each(this.getChildren(), (child: DataType) => {
-            child.bind(calldata, CalldataSection.DATA);
-        });
-    }
-
-    public getId(): string {
-        return this.dataItem.name;
-    }
-
-    public getOffset(): BigNumber {
-        if (this.memblock === undefined) return new BigNumber(0);
-        return this.memblock.getOffset();
-    }
-
-    public getAbsoluteOffset(): BigNumber {
-        if (this.memblock === undefined) return new BigNumber(0);
-        return this.memblock.getAbsoluteOffset();
-    }
-    /*
-        public getSize(): BigNumber {
-            if (this.memblock === undefined) return new BigNumber(0);
-            return this.memblock.getSize();
-        }
-        */
-
-    public getChildren(): DataType[] {
-        return this.children;
-    }
-
-    public getSize(): BigNumber {
-        return this.getHeaderSize().plus(this.getBodySize());
-    }
-
-    public abstract assignValue(value: any): void;
-    public abstract getSignature(): string;
-    public abstract isStatic(): boolean;
-    public abstract getHeaderSize(): BigNumber;
-    public abstract getBodySize(): BigNumber;
-}
-
-export abstract class StaticDataType extends DataType {
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-    }
-}
-
-export abstract class DynamicDataType extends DataType {
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-    }
-}
-
-export class Address extends StaticDataType {
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        expect(Address.matchGrammar(dataItem.type)).to.be.true();
-    }
-
-    public assignValue(value: string) {
-        const evmWordWidth = 32;
-        const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth));
-        this.assignHexValue(hexValue);
-    }
-
-    public getSignature(): string {
-        return `address`;
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        return new BigNumber(32);
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'address';
-    }
-}
-
-export class Bool extends StaticDataType {
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        expect(Bool.matchGrammar(dataItem.type)).to.be.true();
-    }
-
-    public assignValue(value: boolean) {
-        const evmWordWidth = 32;
-        const encodedValue = value === true ? '0x1' : '0x0';
-        const hexValue = ethUtil.bufferToHex(ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth));
-        this.assignHexValue(hexValue);
-    }
-
-    public getSignature(): string {
-        return 'bool';
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        return new BigNumber(32);
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'bool';
-    }
-}
-
-abstract class Number extends StaticDataType {
-    static MAX_WIDTH: number = 256;
-    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
-    width: number = Number.DEFAULT_WIDTH;
-
-    constructor(dataItem: DataItem, matcher: RegExp) {
-        super(dataItem);
-        const matches = matcher.exec(dataItem.type);
-        expect(matches).to.be.not.null();
-        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
-            this.width = parseInt(matches[1]);
-        } else {
-            this.width = 256;
-        }
-    }
-
-    public assignValue(value: BigNumber) {
-        if (value.greaterThan(this.getMaxValue())) {
-            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
-        } else if (value.lessThan(this.getMinValue())) {
-            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
-        }
-
-        const hexBase = 16;
-        const evmWordWidth = 32;
-        let valueBuf: Buffer;
-        if (value.greaterThanOrEqualTo(0)) {
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
-        } else {
-            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
-            // Step 1/3: Convert value to positive binary string
-            const binBase = 2;
-            const valueBin = value.times(-1).toString(binBase);
-
-            // Step 2/3: Invert binary value
-            const bitsInEvmWord = 256;
-            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
-            _.each(valueBin, (bit: string) => {
-                invertedValueBin += bit === '1' ? '0' : '1';
-            });
-            const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-            // Step 3/3: Add 1 to inverted value
-            // The result is the two's-complement represent of the input value.
-            const negativeValue = invertedValue.plus(1);
-
-            // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
-                evmWordWidth,
-            );
-        }
-
-        const encodedValue = ethUtil.bufferToHex(valueBuf);
-        this.assignHexValue(encodedValue);
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        return new BigNumber(32);
-    }
-
-    public abstract getMaxValue(): BigNumber;
-    public abstract getMinValue(): BigNumber;
-}
-
-export class Int extends Number {
-    static matcher = RegExp(
-        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, Int.matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).times(-1);
-    }
-
-    public getSignature(): string {
-        return `int${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class UInt extends Number {
-    static matcher = RegExp(
-        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, UInt.matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getSignature(): string {
-        return `uint${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Byte extends StaticDataType {
-    static matcher = RegExp(
-        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
-    );
-
-    static DEFAULT_WIDTH = 1;
-    width: number = Byte.DEFAULT_WIDTH;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        const matches = Byte.matcher.exec(dataItem.type);
-        expect(matches).to.be.not.null();
-        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
-            this.width = parseInt(matches[2]);
-        } else {
-            this.width = Byte.DEFAULT_WIDTH;
-        }
-    }
-
-    public assignValue(value: string | Buffer) {
-        // Convert value into a buffer and do bounds checking
-        const valueBuf = ethUtil.toBuffer(value);
-        if (valueBuf.byteLength > this.width) {
-            throw new Error(
-                `Tried to assign ${value} (${
-                valueBuf.byteLength
-                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
-            );
-        } else if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        // Store value as hex
-        const evmWordWidth = 32;
-        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
-        const hexValue = ethUtil.bufferToHex(paddedValue);
-
-        this.assignHexValue(hexValue);
-    }
-
-    public getSignature(): string {
-        // Note that `byte` reduces to `bytes1`
-        return `bytes${this.width}`;
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        return new BigNumber(32);
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Bytes extends DynamicDataType {
-    static UNDEFINED_LENGTH = new BigNumber(-1);
-    length: BigNumber = Bytes.UNDEFINED_LENGTH;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        expect(Bytes.matchGrammar(dataItem.type)).to.be.true();
-    }
-
-    public assignValue(value: string | Buffer) {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
-        const paddedBytesForValue = wordsForValue * 32;
-        const paddedValueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
-        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
-        const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
-
-        this.assignHexValue(encodedValue);
-    }
-
-    public getSignature(): string {
-        return 'bytes';
-    }
-
-    public isStatic(): boolean {
-        return false;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        const valueBuf = ethUtil.toBuffer(this.getHexValue());
-        const size = new BigNumber(valueBuf.byteLength);
-        return size;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'bytes';
-    }
-}
-
-export class SolString extends DynamicDataType {
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        expect(SolString.matchGrammar(dataItem.type)).to.be.true();
-    }
-
-    public assignValue(value: string) {
-        const wordsForValue = Math.ceil(value.length / 32);
-        const paddedBytesForValue = wordsForValue * 32;
-        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
-        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-        const encodedValue = ethUtil.bufferToHex(encodedValueBuf);
-
-        this.assignHexValue(encodedValue);
-    }
-
-    public getSignature(): string {
-        return 'string';
-    }
-
-    public isStatic(): boolean {
-        return false;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        const valueBuf = ethUtil.toBuffer(this.getHexValue());
-        const size = new BigNumber(valueBuf.byteLength);
-        return size;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'string';
-    }
-}
-
-export class SolArray extends DynamicDataType {
-    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
-    static UNDEFINED_LENGTH = new BigNumber(-1);
-    length: BigNumber = SolArray.UNDEFINED_LENGTH;
-    type: string = '[undefined]';
-    isLengthDefined: boolean;
-    isStaticArray: boolean; // An array is dynamic if it's lenghth is undefined or if its children are dynamic.
-    private elements: DataType[];
-
-    /*
-    --- Layout 1: Fixed Length Array with Static Types ---
-    Elem1, Elem2, ..., ElemN
-
-    --- Layout 2: Fixed Length Array with Dynamic Types ---
-    PtrToArray, ..., Elem1, Elem2, ..., ElemN
-
-    --- Layout 3: Dynamic Length Array with Static Types ---
-    PtrToArray, ..., ArrayLength, Elem1, Elem2, ..., ElemN
-
-    --- Layout 4: Dynamic Length Array with Dynamic Types ---
-    PtrToArray, ..., ArrayLength, PtrToElem1, PtrToElem2, ..., PtrToElemN, ..., Elem1, Elem2, ..., ElemN
-    */
-
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        const matches = SolArray.matcher.exec(dataItem.type);
-        expect(matches).to.be.not.null();
-        console.log(JSON.stringify(matches));
-        if (matches === null || matches.length !== 3) {
-            throw new Error(`Could not parse array: ${dataItem.type}`);
-        } else if (matches[1] === undefined) {
-            throw new Error(`Could not parse array type: ${dataItem.type}`);
-        } else if (matches[2] === undefined) {
-            throw new Error(`Could not parse array length: ${dataItem.type}`);
-        }
-
-        this.elements = [];
-
-        // Check if length is undefined
-        if (matches[2] === '') {
-            this.type = matches[1];
-            this.length = SolArray.UNDEFINED_LENGTH;
-            this.isLengthDefined = false;
-            this.isStaticArray = false;
-            return;
-        }
-
-        // Parse out array type/length and construct children
-        this.isLengthDefined = true;
-        this.type = matches[1];
-        this.length = new BigNumber(matches[2], 10);
-        if (this.length.lessThan(1)) {
-            throw new Error(`Bad array length: ${JSON.stringify(this.length)}`);
-        }
-        this.constructChildren();
-
-        // Check if we're static or not
-        this.isStaticArray = !(this.elements[0] instanceof Pointer);  //this.elements[0].isStatic();
-        //throw new Error(`Am I static? ${this.isStaticArray}`);
-    }
-
-    private constructChildren() {
-        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-            const childDataItem = {
-                type: this.type,
-                name: `${this.getDataItem().name}[${idx.toString(10)}]`,
-            } as DataItem;
-            const components = this.getDataItem().components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = DataTypeFactory.create(childDataItem, this);
-            this.elements.push(child);
-            if (child instanceof Pointer) {
-                const pointsTo = child.getChildren()[0];
-                this.children.push(pointsTo); // DataType pointing to
-            }
-        }
-    }
-
-    // @TODO: HACKY -- shouldn't really have children for a 
-    /*
-    public getChildren(): DataType[] {
-        if (this.isStatic()) {
-            return [];
-        } else {
-            return this.children;
-        }
-    }*/
-
-    public assignValue(value: any[]) {
-        console.log('GREG'.repeat(15), JSON.stringify(value));
-
-
-        // Sanity check length
-        const valueLength = new BigNumber(value.length);
-        if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
-            throw new Error(
-                `Expected array of length ${JSON.stringify(this.length)}, but got array of length ${JSON.stringify(
-                    valueLength,
-                )}`,
-            );
-        }
-
-        // Assign length if not already set
-        if (this.length === SolArray.UNDEFINED_LENGTH) {
-            this.length = valueLength;
-            this.constructChildren();
-        }
-
-        // Assign values to children
-        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-            const idxNumber = idx.toNumber();
-            this.elements[idxNumber].assignValue(value[idxNumber]);
-        }
-    }
-
-    public getHexValue(): string {
-        let valueBuf = new Buffer("");
-
-        if (this.isLengthDefined === false) {
-            // Must include the array length
-            const lengthBufUnpadded = ethUtil.toBuffer(`0x${this.length.toString(16)}`);
-            const lengthBuf = ethUtil.setLengthLeft(lengthBufUnpadded, 32);
-            valueBuf = lengthBuf;
-        }
-
-        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-            const idxNumber = idx.toNumber();
-            const childValueHex = this.elements[idxNumber].getHexValue();
-            const childValueBuf = ethUtil.toBuffer(childValueHex);
-            valueBuf = Buffer.concat([valueBuf, childValueBuf]);
-        }
-
-        // Convert value buffer to hex
-        const valueHex = ethUtil.bufferToHex(valueBuf);
-        return valueHex;
-    }
-
-    public isStatic(): boolean {
-        return this.isStaticArray;
-    }
-
-    public getHeaderSize(): BigNumber {
-        let size = new BigNumber(0);
-        if (!this.isLengthDefined) {
-            size = new BigNumber(32); // stores length of bytes
-        }
-        return size;
-    }
-
-    public getBodySize(): BigNumber {
-        const evmWordWidth = new BigNumber(32);
-        const body = this.length.times(evmWordWidth);
-        return body;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-
-    public getSignature(): string {
-        let dataItem = {
-            type: this.type,
-            name: 'N/A',
-        } as DataItem;
-        const components = this.getDataItem().components;
-        if (components !== undefined) {
-            dataItem.components = components;
-        }
-        const elementDataType = DataTypeFactory.mapDataItemToDataType(dataItem);
-        const type = elementDataType.getSignature();
-        if (this.length.equals(SolArray.UNDEFINED_LENGTH)) {
-            return `${type}[]`;
-        }
-        return `${type}[${this.length}]`;
-    }
-}
-
-export class Tuple extends DynamicDataType {
-    private length: BigNumber;
-    private childMap: { [key: string]: number };
-    private members: DataType[];
-
-    constructor(dataItem: DataItem) {
-        super(dataItem);
-        expect(Tuple.matchGrammar(dataItem.type)).to.be.true();
-        this.length = new BigNumber(0);
-        this.childMap = {};
-        this.members = [];
-        if (dataItem.components !== undefined) {
-            this.constructChildren(dataItem.components);
-            this.length = new BigNumber(dataItem.components.length);
-        } else {
-            throw new Error('Components undefined');
-        }
-    }
-
-    private constructChildren(dataItems: DataItem[]) {
-        _.each(dataItems, (dataItem: DataItem) => {
-            const childDataItem = {
-                type: dataItem.type,
-                name: `${this.getDataItem().name}.${dataItem.name}`,
-            } as DataItem;
-            const child = DataTypeFactory.create(childDataItem, this);
-            this.childMap[dataItem.name] = this.members.length;
-
-            if (child instanceof Pointer) {
-                this.children.push(child.getChildren()[0]);
-            }
-            this.members.push(child);
-        });
-    }
-
-    private assignValueFromArray(value: any[]) {
-        // Sanity check length
-        const valueLength = new BigNumber(value.length);
-        if (this.length !== SolArray.UNDEFINED_LENGTH && valueLength.equals(this.length) === false) {
-            throw new Error(
-                `Expected array of ${JSON.stringify(
-                    this.length,
-                )} elements, but got array of length ${JSON.stringify(valueLength)}`,
-            );
-        }
-
-        // Assign values to children
-        for (let idx = new BigNumber(0); idx.lessThan(this.length); idx = idx.plus(1)) {
-            const idxNumber = idx.toNumber();
-            this.members[idxNumber].assignValue(value[idxNumber]);
-        }
-    }
-
-    private assignValueFromObject(obj: object) {
-        let childMap = _.cloneDeep(this.childMap);
-        _.forOwn(obj, (value: any, key: string) => {
-            if (key in childMap === false) {
-                throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
-            }
-            this.members[this.childMap[key]].assignValue(value);
-            delete childMap[key];
-        });
-
-        if (Object.keys(childMap).length !== 0) {
-            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
-        }
-    }
-
-    public assignValue(value: any[] | object) {
-        if (value instanceof Array) {
-            this.assignValueFromArray(value);
-        } else if (typeof value === 'object') {
-            this.assignValueFromObject(value);
-        } else {
-            throw new Error(`Unexpected type for ${value}`);
-        }
-    }
-
-    public getHexValue(): string {
-        let paramBufs: Buffer[] = [];
-        _.each(this.members, (member: DataType) => {
-            paramBufs.push(ethUtil.toBuffer(member.getHexValue()));
-        });
-
-        const value = Buffer.concat(paramBufs);
-        const hexValue = ethUtil.bufferToHex(value);
-        return hexValue;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        const evmWordWidth = new BigNumber(32);
-        const size = this.length.times(evmWordWidth);
-        return size;
-    }
-
-    public getSignature(): string {
-        // Compute signature
-        let signature = `(`;
-        _.each(this.members, (member: DataType, i: number) => {
-            signature += member.getSignature();
-            if (i < this.members.length - 1) {
-                signature += ',';
-            }
-        });
-        signature += ')';
-        return signature;
-    }
-
-    public isStatic(): boolean {
-        const isStaticTuple = this.children.length === 0;
-        return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'tuple';
-    }
-}
-
-/* TODO
-class Fixed extends StaticDataType {}
-
-class UFixed extends StaticDataType {}*/
-
-export class Pointer extends StaticDataType {
-    destDataType: DynamicDataType;
-    parentDataType: DataType;
-
-    constructor(destDataType: DynamicDataType, parentDataType: DataType) {
-        const destDataItem = destDataType.getDataItem();
-        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
-        super(dataItem);
-        this.destDataType = destDataType;
-        this.parentDataType = parentDataType;
-        this.children.push(destDataType);
-    }
-
-    /*
-    public assignValue(destDataType: DynamicDataType) {
-        this.destDataType = destDataType;
-    }*/
-
-    public assignValue(value: any) {
-        this.destDataType.assignValue(value);
-    }
-
-    public getHexValue(): string {
-        console.log(
-            '*'.repeat(40),
-            this.destDataType.getAbsoluteOffset().toString(16),
-            '^'.repeat(150),
-            this.parentDataType.getAbsoluteOffset().toString(16),
-        );
-
-        let offset = this.destDataType
-            .getAbsoluteOffset()
-            .minus(this.parentDataType.getAbsoluteOffset())
-            .minus(this.parentDataType.getHeaderSize());
-
-        console.log("OFFSET == ", JSON.stringify(offset), " or in hex -- 0x", offset.toString(16));
-
-        const hexBase = 16;
-        const evmWordWidth = 32;
-        const valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${offset.toString(hexBase)}`), evmWordWidth);
-        const encodedValue = ethUtil.bufferToHex(valueBuf);
-        return encodedValue;
-    }
-
-    public getSignature(): string {
-        return this.destDataType.getSignature();
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-
-    public getHeaderSize(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        return new BigNumber(32);
-    }
-
-}
-
-export class DataTypeFactory {
-    public static mapDataItemToDataType(dataItem: DataItem): DataType {
-        console.log(`Type: ${dataItem.type}`);
-
-        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
-        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
-        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
-        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
-        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
-        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
-        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
-        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
-        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
-
-        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-    }
-
-    public static create(dataItem: DataItem, parentDataType: DataType): DataType {
-        const dataType = DataTypeFactory.mapDataItemToDataType(dataItem);
-        if (dataType.isStatic()) {
-            return dataType;
-        } else {
-            const pointer = new Pointer(dataType, parentDataType);
-            return pointer;
-        }
-
-        throw new Error(`Unrecognized instance type: '${dataType}'`);
-    }
-}
-
-class Queue<T> {
-    private store: T[] = [];
-    push(val: T) {
-        this.store.push(val);
-    }
-    pop(): T | undefined {
-        return this.store.shift();
-    }
-}
-
-export class Method extends DataType {
-    name: string;
-    params: DataType[];
-    private signature: string;
-    selector: string;
-
-    constructor(abi: MethodAbi) {
-        super({ type: 'method', name: abi.name });
-        this.name = abi.name;
-        this.params = [];
-
-        _.each(abi.inputs, (input: DataItem) => {
-            this.params.push(DataTypeFactory.create(input, this));
-        });
-
-        // Compute signature
-        this.signature = `${this.name}(`;
-        _.each(this.params, (param: DataType, i: number) => {
-            this.signature += param.getSignature();
-            if (i < this.params.length - 1) {
-                this.signature += ',';
-            }
-        });
-        this.signature += ')';
-
-        // Compute selector
-        this.selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(this.signature).slice(0, 4)));
-
-        console.log(`--SIGNATURE--\n${this.signature}\n---------\n`);
-        console.log(`--SELECTOR--\n${this.selector}\n---------\n`);
-    }
-
-    public getSignature(): string {
-        return this.signature;
-    }
-
-    public assignValue(args: any[]) {
-        _.each(this.params, (param: DataType, i: number) => {
-            // Assign value to parameter
-            try {
-                param.assignValue(args[i]);
-            } catch (e) {
-                console.log('Failed to assign to ', param.getDataItem().name);
-                throw e;
-            }
-
-            if (param instanceof Pointer) {
-                this.children.push(param.getChildren()[0]);
-            }
-        });
-    }
-
-    public getHexValue(): string {
-        let paramBufs: Buffer[] = [];
-        _.each(this.params, (param: DataType) => {
-            paramBufs.push(ethUtil.toBuffer(param.getHexValue()));
-        });
-
-        const value = Buffer.concat(paramBufs);
-        const hexValue = ethUtil.bufferToHex(value);
-        return hexValue;
-    }
-
-    public encode(args: any[]): string {
-        this.assignValue(args);
-        const calldata = new Calldata(this.selector, this.params.length);
-        calldata.printAnnotated();
-        this.bind(calldata, CalldataSection.PARAMS);
-
-        return calldata.getHexValue();
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-
-    public getHeaderSize(): BigNumber {
-        // Exclude selector
-        return new BigNumber(0);
-    }
-
-    public getBodySize(): BigNumber {
-        const nParams = new BigNumber(this.params.length);
-        const evmWordWidth = new BigNumber(32);
-        const size = nParams.times(evmWordWidth);
-        return size;
-    }
-
-    /*
-    encodeOptimized(args: any[]): string {
-        const calldata = new Memory();
-        // Assign values
-        optimizableParams : StaticDataType = [];
-        _.each(this.params, function(args: any[], i: number, param: DataType) {
-            param.assignValue(args[i]);
-            if (param instanceof DynamicDataType) {
-
-            }
-        });
-
-        // Find non-parameter leaves
-
-
-        return '';
-    } */
-
-    /*
-    decode(rawCalldata: string): any[] {
-        const calldata = new Calldata(this.name, this.params.length);
-        calldata.assignRaw(rawCalldata);
-        let args: any[];
-        let params = this.params;
-        _.each(params, function(args: any[], i: number, param: DataType) {
-            param.decodeFromCalldata(calldata);
-            args.push(param.getValue());
-        });
-
-        return args;
-    }*/
-}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index f46a1812c..d75c9dbf1 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -410,237 +410,237 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
     });
-
-    describe('Array', () => {
-        it('sample', async () => {
-            const testDataItem = { name: 'testArray', type: 'int[2]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
-            console.log(JSON.stringify(dataType, null, 4));
-            console.log('*'.repeat(60));
-            dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-            console.log(JSON.stringify(dataType, null, 4));
-            const hexValue = dataType.getHexValue();
-            console.log('*'.repeat(60));
-            console.log(hexValue);
-        });
-
-        it('sample undefined size', async () => {
-            const testDataItem = { name: 'testArray', type: 'int[]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
-            console.log(JSON.stringify(dataType, null, 4));
-            console.log('*'.repeat(60));
-            dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-            console.log(JSON.stringify(dataType, null, 4));
-            const hexValue = dataType.getHexValue();
-            console.log('*'.repeat(60));
-            console.log(hexValue);
-        });
-
-        it('sample dynamic types', async () => {
-            const testDataItem = { name: 'testArray', type: 'string[]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
-            console.log(JSON.stringify(dataType, null, 4));
-            console.log('*'.repeat(60));
-            dataType.assignValue(['five', 'six', 'seven']);
-            console.log(JSON.stringify(dataType, null, 4));
-            const hexValue = dataType.getHexValue();
-            console.log('*'.repeat(60));
-            console.log(hexValue);
-            const calldata = new AbiEncoder.Calldata('0x01020304', 1);
-            dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
-            console.log('*'.repeat(60));
-            console.log(calldata.getHexValue());
-        });
-    });
-
-    describe('Address', () => {
-        const testAddressDataItem = { name: 'testAddress', type: 'address' };
-        it('Valid Address', async () => {
-            const addressDataType = new AbiEncoder.Address(testAddressDataItem);
-            addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
-            const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
-
-            console.log(addressDataType.getHexValue());
-            console.log(expectedAbiEncodedAddress);
-            expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
-        });
-    });
-
-    describe('Bool', () => {
-        const testBoolDataItem = { name: 'testBool', type: 'bool' };
-        it('True', async () => {
-            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-            boolDataType.assignValue(true);
-            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
-        });
-
-        it('False', async () => {
-            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-            boolDataType.assignValue(false);
-            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
-            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
-        });
-    });
-
-    describe('Integer', () => {
-        const testIntDataItem = { name: 'testInt', type: 'int' };
-        it('Positive - Base case', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(1));
-            const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-        });
-
-        it('Positive', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(437829473));
-            const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-        });
-
-        it('Negative - Base case', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(-1));
-            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-        });
-
-        it('Negative', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(-437829473));
-            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-        });
-
-        // TODO: Add bounds tests + tests for different widths
-    });
-
-    describe('Unsigned Integer', () => {
-        const testIntDataItem = { name: 'testUInt', type: 'uint' };
-        it('Lower Bound', async () => {
-            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-            uintDataType.assignValue(new BigNumber(0));
-            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
-            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-        });
-
-        it('Base Case', async () => {
-            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-            uintDataType.assignValue(new BigNumber(1));
-            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-        });
-
-        it('Random value', async () => {
-            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-            uintDataType.assignValue(new BigNumber(437829473));
-            const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-        });
-
-        // TODO: Add bounds tests + tests for different widths
-    });
-
-    describe('Static Bytes', () => {
-        it('Byte (padded)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x05');
-            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-        });
-
-        it.skip('Byte (no padding)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-
-            // @TODO: This does not catch the Error
-            expect(byteDataType.assignValue('0x5')).to.throw();
-        });
-
-        it('Bytes1', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x05');
-            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-        });
-
-        it('Bytes32 (padded)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
-            const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-        });
-
-        it('Bytes32 (unpadded)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x1a18bf61');
-            const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-        });
-
-        it.skip('Bytes32 - Too long', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-
-            // @TODO: This does not catch the Error
-            expect(
-                byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
-            ).to.throw(
-                `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
-            );
-        });
-    });
-
-    describe('Bytes (Dynamic)', () => {
-        const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
-        it('Less than 32 bytes', async () => {
-            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-            bytesDataType.assignValue('0x010203');
-            const expectedAbiEncodedBytes =
-                '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
-
-            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
-        });
-
-        it('Greater than 32 bytes', async () => {
-            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-            const testValue = '0x' + '61'.repeat(40);
-            bytesDataType.assignValue(testValue);
-            const expectedAbiEncodedBytes =
-                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
-        });
-
-        // @TODO: Add test for throw on half-byte
-        // @TODO: Test with no 0x prefix
-        // @TODO: Test with Buffer as input
-    });
-
-    describe('String', () => {
-        const testStringDataItem = { name: 'testString', type: 'string' };
-        it('Less than 32 bytes', async () => {
-            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-            stringDataType.assignValue('five');
-            const expectedAbiEncodedString =
-                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-
-            console.log(stringDataType.getHexValue());
-            console.log(expectedAbiEncodedString);
-            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
-        });
-
-        it('Greater than 32 bytes', async () => {
-            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-            const testValue = 'a'.repeat(40);
-            stringDataType.assignValue(testValue);
-            const expectedAbiEncodedString =
-                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
-        });
-    });
+    /*
+        describe('Array', () => {
+            it('sample', async () => {
+                const testDataItem = { name: 'testArray', type: 'int[2]' };
+                const dataType = new AbiEncoder.SolArray(testDataItem);
+                console.log(JSON.stringify(dataType, null, 4));
+                console.log('*'.repeat(60));
+                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+                console.log(JSON.stringify(dataType, null, 4));
+                const hexValue = dataType.getHexValue();
+                console.log('*'.repeat(60));
+                console.log(hexValue);
+            });
+    
+            it('sample undefined size', async () => {
+                const testDataItem = { name: 'testArray', type: 'int[]' };
+                const dataType = new AbiEncoder.SolArray(testDataItem);
+                console.log(JSON.stringify(dataType, null, 4));
+                console.log('*'.repeat(60));
+                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+                console.log(JSON.stringify(dataType, null, 4));
+                const hexValue = dataType.getHexValue();
+                console.log('*'.repeat(60));
+                console.log(hexValue);
+            });
+    
+            it('sample dynamic types', async () => {
+                const testDataItem = { name: 'testArray', type: 'string[]' };
+                const dataType = new AbiEncoder.SolArray(testDataItem);
+                console.log(JSON.stringify(dataType, null, 4));
+                console.log('*'.repeat(60));
+                dataType.assignValue(['five', 'six', 'seven']);
+                console.log(JSON.stringify(dataType, null, 4));
+                const hexValue = dataType.getHexValue();
+                console.log('*'.repeat(60));
+                console.log(hexValue);
+                const calldata = new AbiEncoder.Calldata('0x01020304', 1);
+                dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
+                console.log('*'.repeat(60));
+                console.log(calldata.getHexValue());
+            });
+        });
+    
+        describe('Address', () => {
+            const testAddressDataItem = { name: 'testAddress', type: 'address' };
+            it('Valid Address', async () => {
+                const addressDataType = new AbiEncoder.Address(testAddressDataItem);
+                addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
+                const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+    
+                console.log(addressDataType.getHexValue());
+                console.log(expectedAbiEncodedAddress);
+                expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
+            });
+        });
+    
+        describe('Bool', () => {
+            const testBoolDataItem = { name: 'testBool', type: 'bool' };
+            it('True', async () => {
+                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+                boolDataType.assignValue(true);
+                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
+                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+            });
+    
+            it('False', async () => {
+                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+                boolDataType.assignValue(false);
+                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
+                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+            });
+        });
+    
+        describe('Integer', () => {
+            const testIntDataItem = { name: 'testInt', type: 'int' };
+            it('Positive - Base case', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(1));
+                const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            it('Positive', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(437829473));
+                const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            it('Negative - Base case', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(-1));
+                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            it('Negative', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(-437829473));
+                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            // TODO: Add bounds tests + tests for different widths
+        });
+    
+        describe('Unsigned Integer', () => {
+            const testIntDataItem = { name: 'testUInt', type: 'uint' };
+            it('Lower Bound', async () => {
+                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+                uintDataType.assignValue(new BigNumber(0));
+                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
+                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+            });
+    
+            it('Base Case', async () => {
+                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+                uintDataType.assignValue(new BigNumber(1));
+                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+            });
+    
+            it('Random value', async () => {
+                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+                uintDataType.assignValue(new BigNumber(437829473));
+                const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+            });
+    
+            // TODO: Add bounds tests + tests for different widths
+        });
+    
+        describe('Static Bytes', () => {
+            it('Byte (padded)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x05');
+                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it.skip('Byte (no padding)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+    
+                // @TODO: This does not catch the Error
+                expect(byteDataType.assignValue('0x5')).to.throw();
+            });
+    
+            it('Bytes1', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x05');
+                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it('Bytes32 (padded)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
+                const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it('Bytes32 (unpadded)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x1a18bf61');
+                const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it.skip('Bytes32 - Too long', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+    
+                // @TODO: This does not catch the Error
+                expect(
+                    byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
+                ).to.throw(
+                    `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
+                );
+            });
+        });
+    
+        describe('Bytes (Dynamic)', () => {
+            const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
+            it('Less than 32 bytes', async () => {
+                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+                bytesDataType.assignValue('0x010203');
+                const expectedAbiEncodedBytes =
+                    '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
+    
+                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+            });
+    
+            it('Greater than 32 bytes', async () => {
+                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+                const testValue = '0x' + '61'.repeat(40);
+                bytesDataType.assignValue(testValue);
+                const expectedAbiEncodedBytes =
+                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+            });
+    
+            // @TODO: Add test for throw on half-byte
+            // @TODO: Test with no 0x prefix
+            // @TODO: Test with Buffer as input
+        });
+    
+        describe('String', () => {
+            const testStringDataItem = { name: 'testString', type: 'string' };
+            it('Less than 32 bytes', async () => {
+                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+                stringDataType.assignValue('five');
+                const expectedAbiEncodedString =
+                    '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+    
+                console.log(stringDataType.getHexValue());
+                console.log(expectedAbiEncodedString);
+                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+            });
+    
+            it('Greater than 32 bytes', async () => {
+                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+                const testValue = 'a'.repeat(40);
+                stringDataType.assignValue(testValue);
+                const expectedAbiEncodedString =
+                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+            });
+        });*/
 });
-- 
cgit v1.2.3


From 41e01e98064b129f588d72ed25267f4865c58f5c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 18:59:27 -0800
Subject: making progress on basic example

---
 packages/order-utils/test/abi/data_type.ts      | 15 +++++++++------
 packages/order-utils/test/abi/evm_data_types.ts |  7 ++++---
 packages/order-utils/test/abi_encoder_test.ts   | 10 +++++++---
 3 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 201eb89f9..c1e352508 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -95,15 +95,17 @@ export abstract class MemberDataType extends DataType {
     private members: DataType[];
     private isArray: boolean;
     protected arrayLength: number | undefined;
+    protected arrayElementType: string | undefined;
 
 
-    public constructor(dataItem: DataItem, isArray: boolean = false, arrayLength?: number) {
+    public constructor(dataItem: DataItem, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
         super(dataItem);
 
         this.memberMap = {};
         this.members = [];
         this.isArray = isArray;
         this.arrayLength = arrayLength;
+        this.arrayElementType = arrayElementType;
         if (isArray && arrayLength !== undefined) {
             [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
         } else if (!isArray) {
@@ -119,10 +121,10 @@ export abstract class MemberDataType extends DataType {
 
         let members: DataType[] = [];
         let memberMap: MemberMap = {};
-        _.each(dataItem.components, (dataItem: DataItem) => {
+        _.each(dataItem.components, (memberItem: DataItem) => {
             const childDataItem = {
-                type: dataItem.type,
-                name: `${dataItem.name}.${dataItem.name}`,
+                type: memberItem.type,
+                name: `${dataItem.name}.${memberItem.name}`,
             } as DataItem;
             const child = DataTypeFactory.create(childDataItem, this);
             members.push(child);
@@ -133,12 +135,13 @@ export abstract class MemberDataType extends DataType {
     }
 
     private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        console.log(dataItem);
         let members: DataType[] = [];
         let memberMap: MemberMap = {};
         const range = _.range(length);
         _.each(range, (idx: number) => {
             const childDataItem = {
-                type: dataItem.type,
+                type: this.arrayElementType,
                 name: `${dataItem.name}[${idx.toString(10)}]`,
             } as DataItem;
             const components = dataItem.components;
@@ -164,7 +167,7 @@ export abstract class MemberDataType extends DataType {
         }
 
         let members = this.members;
-        if (this.arrayLength === undefined) {
+        if (this.isArray && this.arrayLength === undefined) {
             [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
         }
 
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index 4dffedb8d..1bd4f0d51 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -347,9 +347,10 @@ export class SolArray extends MemberDataType {
         }
 
         const isArray = true;
+        const arrayElementType = matches[1];
         const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
-        super(dataItem, isArray, arrayLength);
-        this.elementType = matches[1];
+        super(dataItem, isArray, arrayLength, arrayElementType);
+        this.elementType = arrayElementType;
         this.arraySignature = this.computeSignature();
     }
 
@@ -388,7 +389,7 @@ export class Method extends MemberDataType {
     public selector: string;
 
     constructor(abi: MethodAbi) {
-        super({ type: 'method', name: abi.name });
+        super({ type: 'method', name: abi.name, components: abi.inputs });
         this.methodSignature = this.computeSignature();
         this.selector = this.methodSelector = this.computeSelector();
 
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index d75c9dbf1..6655af1ff 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -18,13 +18,15 @@ import * as AbiEncoder from './abi/abi_encoder';
 
 import * as AbiSamples from './abi_samples';
 
+AbiEncoder.DataTypeFactory.setImpl(new AbiEncoder.EvmDataTypeFactoryImpl());
+
 chaiSetup.configure();
 const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
     describe.only('ABI Tests at Method Level', () => {
 
-        it('Crazy ABI', async () => {
+        it.skip('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
@@ -89,8 +91,9 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it('Crazy ABI #1', async () => {
+        it.skip('Crazy ABI #1', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
+
             const args = [
                 new BigNumber(256745454),
                 new BigNumber(-256745454),
@@ -115,6 +118,7 @@ describe.only('ABI Encoder', () => {
 
         it('Types with default widths', async () => {
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
+            console.log(method);
             const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
             const calldata = method.encode(args);
             console.log(calldata);
@@ -325,7 +329,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it('Yessir', async () => {
+        it.only('Yessir', async () => {
             const method = new AbiEncoder.Method(AbiSamples.simpleAbi);
             const calldata = method.encode([new BigNumber(5), 'five']);
             console.log(calldata);
-- 
cgit v1.2.3


From 3027e6bc0db9d0722f0dcf09f84505ad8440e65b Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 20:18:23 -0800
Subject: resolved issue with value.greaterThan

---
 packages/order-utils/test/abi/data_type.ts      | 5 +++--
 packages/order-utils/test/abi/evm_data_types.ts | 1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index c1e352508..be7ae6154 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -32,6 +32,7 @@ export abstract class PayloadDataType extends DataType {
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
+        //console.log();
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
@@ -173,8 +174,8 @@ export abstract class MemberDataType extends DataType {
 
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
         const memberBlocks: CalldataBlock[] = [];
-        _.each(members, (member: DataType) => {
-            const block = member.generateCalldataBlock(value, methodBlock);
+        _.each(members, (member: DataType, idx: number) => {
+            const block = member.generateCalldataBlock(value[idx], methodBlock);
             memberBlocks.push(block);
         });
         methodBlock.setMembers(memberBlocks);
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index 1bd4f0d51..fcced646a 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -86,6 +86,7 @@ abstract class Number extends PayloadDataType {
     }
 
     public encodeValue(value: BigNumber): Buffer {
+        console.log(value);
         if (value.greaterThan(this.getMaxValue())) {
             throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
         } else if (value.lessThan(this.getMinValue())) {
-- 
cgit v1.2.3


From 58177060a49917d0de88e6a58559b13211127efe Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 20:22:48 -0800
Subject: works for simple case

---
 packages/order-utils/test/abi/calldata.ts     | 3 ++-
 packages/order-utils/test/abi_encoder_test.ts | 4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 725bdce62..aaad332f8 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -81,7 +81,7 @@ export class DependentCalldataBlock extends CalldataBlock {
     private parent: CalldataBlock;
     private dependency: CalldataBlock;
 
-    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, parent: CalldataBlock, dependency: CalldataBlock) {
+    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
         super(name, signature, /*offsetInBytes,*/ headerSizeInBytes, bodySizeInBytes, relocatable);
@@ -174,6 +174,7 @@ export class Calldata {
         let block: CalldataBlock | undefined;
         let offset = 0;
         while ((block = blockQueue.pop()) !== undefined) {
+            console.log(block.getName());
             block.setOffset(offset);
             if (block instanceof DependentCalldataBlock) {
                 blockQueue.push(block.getDependency());
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 6655af1ff..0455169a3 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -116,7 +116,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it('Types with default widths', async () => {
+        it.skip('Types with default widths', async () => {
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
             console.log(method);
             const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
@@ -329,7 +329,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Yessir', async () => {
+        it('Yessir', async () => {
             const method = new AbiEncoder.Method(AbiSamples.simpleAbi);
             const calldata = method.encode([new BigNumber(5), 'five']);
             console.log(calldata);
-- 
cgit v1.2.3


From addfe85f088fc1aa31638acdd73bae560afceb27 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 21:48:06 -0800
Subject: passing tests slowly but surely

---
 packages/order-utils/test/abi/calldata.ts     | 16 +++++++++++++---
 packages/order-utils/test/abi/data_type.ts    |  7 ++++++-
 packages/order-utils/test/abi_encoder_test.ts |  5 +++--
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index aaad332f8..74f0c0924 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -91,10 +91,15 @@ export class DependentCalldataBlock extends CalldataBlock {
 
     public toBuffer(): Buffer {
         const dependencyOffset = this.dependency.getOffsetInBytes();
+        console.log("Dependency Offset - ", dependencyOffset);
         const parentOffset = this.parent.getOffsetInBytes();
+        console.log("Parent Offset - ", parentOffset);
         const parentHeaderSize = this.parent.getHeaderSizeInBytes();
-        const pointer = dependencyOffset - parentOffset + parentHeaderSize;
-        const pointerBuf = new Buffer(`0x${pointer.toString(16)}`);
+        console.log("Parent Header size - ", parentHeaderSize);
+        const pointer: number = (dependencyOffset - parentOffset) + parentHeaderSize;
+        console.log("DAT PTR = ", pointer);
+        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
+        console.log("Chye - ", pointerBuf);
         const evmWordWidthInBytes = 32;
         const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
         return pointerBufPadded;
@@ -122,7 +127,7 @@ export class MemberCalldataBlock extends CalldataBlock {
             bodySizeInBytes += member.getSizeInBytes();
         });
         this.members = members;
-        this.setBodySize(bodySizeInBytes);
+        this.setBodySize(0);
     }
 
     public setHeader(header: Buffer) {
@@ -176,7 +181,9 @@ export class Calldata {
         while ((block = blockQueue.pop()) !== undefined) {
             console.log(block.getName());
             block.setOffset(offset);
+            offset += block.getSizeInBytes();
             if (block instanceof DependentCalldataBlock) {
+                console.log(block.getDependency());
                 blockQueue.push(block.getDependency());
             } else if (block instanceof MemberCalldataBlock) {
                 _.each(block.getMembers(), (member: CalldataBlock) => {
@@ -185,8 +192,11 @@ export class Calldata {
             }
         }
 
+        console.log(this.root);
+
         // Fetch values using same technique
         const valueBufs: Buffer[] = [selectorBuffer];
+        blockQueue.push(this.root);
         while ((block = blockQueue.pop()) !== undefined) {
             valueBufs.push(block.toBuffer());
 
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index be7ae6154..5311ffb81 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -167,12 +167,17 @@ export abstract class MemberDataType extends DataType {
             );
         }
 
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
+
         let members = this.members;
         if (this.isArray && this.arrayLength === undefined) {
             [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
+
+            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
+            methodBlock.setHeader(lenBuf);
         }
 
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
+
         const memberBlocks: CalldataBlock[] = [];
         _.each(members, (member: DataType, idx: number) => {
             const block = member.generateCalldataBlock(value[idx], methodBlock);
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 0455169a3..e600542b8 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -116,7 +116,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it.skip('Types with default widths', async () => {
+        it('Types with default widths', async () => {
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
             console.log(method);
             const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
@@ -303,7 +303,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it('Fixed Length Array / Static Members ABI', async () => {
+        it.only('Fixed Length Array / Static Members ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
             const calldata = method.encode(args);
@@ -338,6 +338,7 @@ describe.only('ABI Encoder', () => {
 
         it('Array ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
+            console.log(method);
             const calldata = method.encode([['five', 'six', 'seven']]);
             console.log(method.getSignature());
             console.log(method.selector);
-- 
cgit v1.2.3


From 20f1526c7d0e1edb4a1de8e8a26811ae81b609dc Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 21:59:37 -0800
Subject: arrays working

---
 packages/order-utils/test/abi/calldata.ts     | 2 +-
 packages/order-utils/test/abi/data_type.ts    | 4 +++-
 packages/order-utils/test/abi_encoder_test.ts | 4 ++--
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 74f0c0924..c1630c34a 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -96,7 +96,7 @@ export class DependentCalldataBlock extends CalldataBlock {
         console.log("Parent Offset - ", parentOffset);
         const parentHeaderSize = this.parent.getHeaderSizeInBytes();
         console.log("Parent Header size - ", parentHeaderSize);
-        const pointer: number = (dependencyOffset - parentOffset) + parentHeaderSize;
+        const pointer: number = dependencyOffset - (parentOffset + parentHeaderSize);
         console.log("DAT PTR = ", pointer);
         const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
         console.log("Chye - ", pointerBuf);
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 5311ffb81..72d270bf1 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -102,6 +102,8 @@ export abstract class MemberDataType extends DataType {
     public constructor(dataItem: DataItem, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
         super(dataItem);
 
+        console.log('*'.repeat(40), arrayLength);
+
         this.memberMap = {};
         this.members = [];
         this.isArray = isArray;
@@ -243,7 +245,7 @@ export abstract class MemberDataType extends DataType {
         */
 
         if (this.isArray && this.arrayLength === undefined) {
-            return true;
+            return false;
         }
 
         // Search for dependent members
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index e600542b8..4c571434e 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -259,7 +259,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it('Fixed Lenfgth Array / Dynamic Members', async () => {
+        it.only('Fixed Lenfgth Array / Dynamic Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
             const args = [["Brave", "New", "World"]];
             const calldata = method.encode(args);
@@ -303,7 +303,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it.only('Fixed Length Array / Static Members ABI', async () => {
+        it('Fixed Length Array / Static Members ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
             const calldata = method.encode(args);
-- 
cgit v1.2.3


From 59206c387e702492d22e975acf806ebe7de36bfd Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 22:24:24 -0800
Subject: Works for types with default widths

---
 packages/order-utils/test/abi/calldata.ts     | 24 ++++++++++++++----------
 packages/order-utils/test/abi/data_type.ts    |  9 ++-------
 packages/order-utils/test/abi_encoder_test.ts |  6 +++---
 3 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index c1630c34a..dc67a731e 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -91,15 +91,10 @@ export class DependentCalldataBlock extends CalldataBlock {
 
     public toBuffer(): Buffer {
         const dependencyOffset = this.dependency.getOffsetInBytes();
-        console.log("Dependency Offset - ", dependencyOffset);
         const parentOffset = this.parent.getOffsetInBytes();
-        console.log("Parent Offset - ", parentOffset);
         const parentHeaderSize = this.parent.getHeaderSizeInBytes();
-        console.log("Parent Header size - ", parentHeaderSize);
         const pointer: number = dependencyOffset - (parentOffset + parentHeaderSize);
-        console.log("DAT PTR = ", pointer);
         const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
-        console.log("Chye - ", pointerBuf);
         const evmWordWidthInBytes = 32;
         const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
         return pointerBufPadded;
@@ -114,11 +109,13 @@ export class MemberCalldataBlock extends CalldataBlock {
     private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
     private header: Buffer | undefined;
     private members: CalldataBlock[];
+    private contiguous: boolean;
 
-    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean) {
+    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, contiguous: boolean) {
         super(name, signature, /*offsetInBytes,*/ 0, 0, relocatable);
         this.members = [];
         this.header = undefined;
+        this.contiguous = contiguous;
     }
 
     public setMembers(members: CalldataBlock[]) {
@@ -130,6 +127,10 @@ export class MemberCalldataBlock extends CalldataBlock {
         this.setBodySize(0);
     }
 
+    public isContiguous(): boolean {
+        return true;
+    }
+
     public setHeader(header: Buffer) {
         this.setHeaderSize(header.byteLength);
         this.header = header;
@@ -150,6 +151,9 @@ class Queue<T> {
     push(val: T) {
         this.store.push(val);
     }
+    pushFront(val: T) {
+        this.store.unshift(val);
+    }
     pop(): T | undefined {
         return this.store.shift();
     }
@@ -186,8 +190,8 @@ export class Calldata {
                 console.log(block.getDependency());
                 blockQueue.push(block.getDependency());
             } else if (block instanceof MemberCalldataBlock) {
-                _.each(block.getMembers(), (member: CalldataBlock) => {
-                    blockQueue.push(member);
+                _.eachRight(block.getMembers(), (member: CalldataBlock) => {
+                    blockQueue.pushFront(member);
                 });
             }
         }
@@ -203,8 +207,8 @@ export class Calldata {
             if (block instanceof DependentCalldataBlock) {
                 blockQueue.push(block.getDependency());
             } else if (block instanceof MemberCalldataBlock) {
-                _.each(block.getMembers(), (member: CalldataBlock) => {
-                    blockQueue.push(member);
+                _.eachRight(block.getMembers(), (member: CalldataBlock) => {
+                    blockQueue.pushFront(member);
                 });
             }
         }
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 72d270bf1..0783b9c56 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -32,7 +32,6 @@ export abstract class PayloadDataType extends DataType {
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
-        //console.log();
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
@@ -101,9 +100,6 @@ export abstract class MemberDataType extends DataType {
 
     public constructor(dataItem: DataItem, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
         super(dataItem);
-
-        console.log('*'.repeat(40), arrayLength);
-
         this.memberMap = {};
         this.members = [];
         this.isArray = isArray;
@@ -138,7 +134,6 @@ export abstract class MemberDataType extends DataType {
     }
 
     private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
-        console.log(dataItem);
         let members: DataType[] = [];
         let memberMap: MemberMap = {};
         const range = _.range(length);
@@ -169,7 +164,7 @@ export abstract class MemberDataType extends DataType {
             );
         }
 
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), this.isStatic(), false);
 
         let members = this.members;
         if (this.isArray && this.arrayLength === undefined) {
@@ -190,7 +185,7 @@ export abstract class MemberDataType extends DataType {
     }
 
     protected generateCalldataBlockFromObject(obj: object): MemberCalldataBlock {
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), false);
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), this.isStatic(), false);
         const memberBlocks: CalldataBlock[] = [];
         let childMap = _.cloneDeep(this.memberMap);
         _.forOwn(obj, (value: any, key: string) => {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 4c571434e..404f160fd 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -116,7 +116,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it('Types with default widths', async () => {
+        it.only('Types with default widths', async () => {
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
             console.log(method);
             const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
@@ -201,7 +201,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it('Multidimensional Arrays / Static Members', async () => {
+        it.only('Multidimensional Arrays / Static Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
 
             // Eight 3-dimensional arrays of uint8[2][2][2]
@@ -259,7 +259,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Fixed Lenfgth Array / Dynamic Members', async () => {
+        it('Fixed Lenfgth Array / Dynamic Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
             const args = [["Brave", "New", "World"]];
             const calldata = method.encode(args);
-- 
cgit v1.2.3


From bb7dd2373893366dcab0fe1c4cffe0c1e31af837 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 23:00:20 -0800
Subject: passing 18 tests

---
 packages/order-utils/test/abi/calldata.ts       | 54 +++++++++++++++++++++++--
 packages/order-utils/test/abi/data_type.ts      | 13 ++++--
 packages/order-utils/test/abi/evm_data_types.ts |  1 +
 packages/order-utils/test/abi_encoder_test.ts   |  4 +-
 4 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index dc67a731e..37dd30e57 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -1,4 +1,5 @@
 import ethUtil = require('ethereumjs-util');
+import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
 var _ = require('lodash');
 
 export abstract class CalldataBlock {
@@ -157,12 +158,18 @@ class Queue<T> {
     pop(): T | undefined {
         return this.store.shift();
     }
+    merge(q: Queue<T>) {
+        this.store = this.store.concat(q.store);
+    }
+    mergeFront(q: Queue<T>) {
+        this.store = q.store.concat(this.store);
+    }
 }
 
 export class Calldata {
     private selector: string;
     private sizeInBytes: number;
-    private root: CalldataBlock | undefined;
+    private root: MemberCalldataBlock | undefined;
 
     constructor() {
         this.selector = '0x';
@@ -170,12 +177,53 @@ export class Calldata {
         this.root = undefined;
     }
 
+    private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> {
+        const blockQueue = new Queue<CalldataBlock>();
+        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof MemberCalldataBlock) {
+                blockQueue.mergeFront(this.createQueue(member));
+            } else {
+                blockQueue.pushFront(member);
+            }
+        });
+
+        // Children
+        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof DependentCalldataBlock) {
+                const dependency = member.getDependency();
+                if (dependency instanceof MemberCalldataBlock) {
+                    blockQueue.merge(this.createQueue(dependency));
+                } else {
+                    blockQueue.push(dependency);
+                }
+            }
+        });
+
+        blockQueue.pushFront(memberBlock);
+        return blockQueue;
+    }
+
     public toHexString(): string {
         let selectorBuffer = ethUtil.toBuffer(this.selector);
         if (this.root === undefined) {
             throw new Error('expected root');
         }
 
+        const offsetQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        while ((block = offsetQueue.pop()) !== undefined) {
+            block.setOffset(offset);
+            offset += block.getSizeInBytes();
+        }
+
+        const valueQueue = this.createQueue(this.root);
+        const valueBufs: Buffer[] = [selectorBuffer];
+        while ((block = valueQueue.pop()) !== undefined) {
+            valueBufs.push(block.toBuffer());
+        }
+
+        /*
         const blockQueue = new Queue<CalldataBlock>();
         blockQueue.push(this.root);
 
@@ -211,7 +259,7 @@ export class Calldata {
                     blockQueue.pushFront(member);
                 });
             }
-        }
+        }*/
 
         const combinedBuffers = Buffer.concat(valueBufs);
         const hexValue = ethUtil.bufferToHex(combinedBuffers);
@@ -230,7 +278,7 @@ export class Calldata {
         return "";
     }
 
-    public setRoot(block: CalldataBlock) {
+    public setRoot(block: MemberCalldataBlock) {
         this.root = block;
         this.sizeInBytes += block.getSizeInBytes();
     }
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 0783b9c56..7f110c4fc 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -43,7 +43,7 @@ export abstract class PayloadDataType extends DataType {
 
     public encode(value: any, calldata: Calldata): void {
         const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block);
+        // calldata.setRoot(block);
     }
 
     public isStatic(): boolean {
@@ -78,7 +78,7 @@ export abstract class DependentDataType extends DataType {
 
     public encode(value: any, calldata: Calldata = new Calldata()): void {
         const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block);
+        //calldata.setRoot(block);
     }
 
     public isStatic(): boolean {
@@ -125,15 +125,20 @@ export abstract class MemberDataType extends DataType {
                 type: memberItem.type,
                 name: `${dataItem.name}.${memberItem.name}`,
             } as DataItem;
+            const components = memberItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
             const child = DataTypeFactory.create(childDataItem, this);
+            memberMap[memberItem.name] = members.length;
             members.push(child);
-            memberMap[dataItem.name] = members.length;
         });
 
         return [members, memberMap];
     }
 
     private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        console.log('!'.repeat(30), dataItem);
         let members: DataType[] = [];
         let memberMap: MemberMap = {};
         const range = _.range(length);
@@ -147,8 +152,8 @@ export abstract class MemberDataType extends DataType {
                 childDataItem.components = components;
             }
             const child = DataTypeFactory.create(childDataItem, this);
-            members.push(child);
             memberMap[idx.toString(10)] = members.length;
+            members.push(child);
         });
 
         return [members, memberMap];
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index fcced646a..dfa541e80 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -315,6 +315,7 @@ export class Tuple extends MemberDataType {
     private tupleSignature: string;
 
     constructor(dataItem: DataItem) {
+        console.log(dataItem);
         super(dataItem);
         if (!Tuple.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 404f160fd..984507923 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -116,7 +116,7 @@ describe.only('ABI Encoder', () => {
         });
 
 
-        it.only('Types with default widths', async () => {
+        it('Types with default widths', async () => {
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
             console.log(method);
             const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
@@ -201,7 +201,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.only('Multidimensional Arrays / Static Members', async () => {
+        it('Multidimensional Arrays / Static Members', async () => {
             const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
 
             // Eight 3-dimensional arrays of uint8[2][2][2]
-- 
cgit v1.2.3


From 707a93e9f95e2adac992dc0e7903b7b1646c78c5 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Fri, 9 Nov 2018 23:00:58 -0800
Subject: Refactor passing all regression tests

---
 packages/order-utils/test/abi_encoder_test.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 984507923..fa0fa23c1 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -26,7 +26,7 @@ const expect = chai.expect;
 describe.only('ABI Encoder', () => {
     describe.only('ABI Tests at Method Level', () => {
 
-        it.skip('Crazy ABI', async () => {
+        it('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
@@ -91,7 +91,7 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
-        it.skip('Crazy ABI #1', async () => {
+        it('Crazy ABI #1', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
 
             const args = [
-- 
cgit v1.2.3


From a9e3d489d60df1be4805f1c84f136eb127fef949 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 12 Nov 2018 12:49:03 -0800
Subject: Tests for nested tuples -- couldnt test because not supported by
 reference ABI encoder

---
 packages/order-utils/test/abi/data_type.ts    |  2 +-
 packages/order-utils/test/abi_encoder_test.ts | 74 ++++++++++++++++++++++
 packages/order-utils/test/abi_samples.ts      | 89 +++++++++++++++++++++++++++
 3 files changed, 164 insertions(+), 1 deletion(-)

diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 7f110c4fc..532407f52 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -195,7 +195,7 @@ export abstract class MemberDataType extends DataType {
         let childMap = _.cloneDeep(this.memberMap);
         _.forOwn(obj, (value: any, key: string) => {
             if (key in childMap === false) {
-                throw new Error(`Could not assign tuple to object: unrecognized key '${key}'`);
+                throw new Error(`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`);
             }
             const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
             memberBlocks.push(block);
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index fa0fa23c1..0db5f4281 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -387,6 +387,80 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
 
+        it.skip('Nested Tuples', async () => {
+            // Couldn't get nested tuples to work with Remix
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.nestedTuples);
+            const firstTuple = {
+                someUint32: new BigNumber(30472),
+                nestedTuple: {
+                    someUint: new BigNumber('48384725243211555532'),
+                    someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
+                }
+            };
+            const secondTuple = {
+                someUint: new BigNumber(2984237422),
+                someStr: 'This string will exceed 256 bits, so it will spill into the next word of memory.',
+                nestedTuple: {
+                    someUint32: new BigNumber(23),
+                    secondNestedTuple: {
+                        someUint: new BigNumber(234324),
+                        someStr: 'Im also a short string -- oops I just got loooooooooooooooooonger!',
+                        someBytes: '0x23847287fff3472984723498ff23487324987aaa237438911873429472ba',
+                        someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
+                    }
+                },
+                someBytes: '0x2834y3947289423u489aaaff4783924739847489',
+                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699afaf',
+            };
+            const thirdTuple = {
+                'someUint': new BigNumber(37422),
+                'someStr': 'This into the next word of memory. string will exceed 256 bits, so it will spill.',
+                'nestedTuple': {
+                    someUint32: new BigNumber(23999222),
+                    'secondNestedTuple': {
+                        'someUint': new BigNumber(324),
+                        'someStr': 'Im also a short st',
+                        'someBytes': '0x723498ff2348732498723847287fff3472984aaa237438911873429472ba',
+                        'someAddress': '0x46dafa5ebde1f4699f498e41d2489571d3221892'
+                    }
+                },
+                'someBytes': '0x947289423u489aaaff472834y383924739847489',
+                'someAddress': '0x46dafa5ebde1f46e41d2489571d322189299afaf',
+            };
+            const fourthTuple = {
+                'someUint': new BigNumber(222283488822),
+                'someStr': 'exceed 256 bits, so it will spill into the. This string will next word of memory.',
+                'nestedTuple': {
+                    someUint32: new BigNumber(2300),
+                    'secondNestedTuple': {
+                        'someUint': new BigNumber(343224),
+                        'someStr': 'The alphabet backwards is arguably easier to say if thats the way you learned the first time.',
+                        'someBytes': '0x87324987aaa23743891187323847287fff3472984723498ff234429472ba',
+                        'someAddress': '0x71d322189246dafa5ebe41d24895de1f4699f498'
+                    }
+                },
+                'someBytes': '0x2783924739847488343947289423u489aaaff490',
+                'someAddress': '0xebde1d322189246dafa1f4699afafe41d2489575',
+            };
+            const args = [
+                [firstTuple],
+                [secondTuple, thirdTuple, fourthTuple]
+            ];
+
+            console.log('*'.repeat(250), method, '*'.repeat(250));
+
+
+            const calldata = method.encode(args);
+            console.log(method.getSignature());
+            console.log(method.selector);
+            console.log(JSON.stringify(args));
+
+            console.log(calldata);
+            const expectedCalldata = '0x';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
         it.skip('Object ABI (Object input - Missing Key)', async () => {
             const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
             const calldata = method.encode([{ someUint: new BigNumber(5) }]);
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index 82427986a..3f7b1a927 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -547,6 +547,95 @@ export const crazyAbi = {
     type: 'function',
 } as MethodAbi;
 
+export const nestedTuples = {
+    constant: false,
+    inputs: [
+        {
+            name: 'firstTuple',
+            type: 'tuple[1]',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'nestedTuple',
+                    type: 'tuple',
+                    components: [
+                        {
+                            name: 'someUint',
+                            type: 'uint256',
+                        },
+                        {
+                            name: 'someAddress',
+                            type: 'address',
+                        },
+                    ],
+                },
+            ],
+        },
+        {
+            name: 'secondTuple',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                {
+                    name: 'nestedTuple',
+                    type: 'tuple',
+                    components: [
+                        {
+                            name: 'someUint32',
+                            type: 'uint32',
+                        },
+                        {
+                            name: 'secondNestedTuple',
+                            type: 'tuple',
+                            components: [
+                                {
+                                    name: 'someUint',
+                                    type: 'uint256',
+                                },
+                                {
+                                    name: 'someStr',
+                                    type: 'string',
+                                },
+                                {
+                                    name: 'someBytes',
+                                    type: 'bytes',
+                                },
+                                {
+                                    name: 'someAddress',
+                                    type: 'address',
+                                },
+                            ],
+                        },
+                    ],
+                },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const simpleAbi2 = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From 13d456fda1da19c8227acb2bf23106bcbdaf6f12 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 12 Nov 2018 13:06:45 -0800
Subject: removed old code

---
 packages/order-utils/test/abi/calldata.ts | 38 -------------------------------
 1 file changed, 38 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 37dd30e57..94f6a5571 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -223,44 +223,6 @@ export class Calldata {
             valueBufs.push(block.toBuffer());
         }
 
-        /*
-        const blockQueue = new Queue<CalldataBlock>();
-        blockQueue.push(this.root);
-
-        // Assign locations in breadth-first manner
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        while ((block = blockQueue.pop()) !== undefined) {
-            console.log(block.getName());
-            block.setOffset(offset);
-            offset += block.getSizeInBytes();
-            if (block instanceof DependentCalldataBlock) {
-                console.log(block.getDependency());
-                blockQueue.push(block.getDependency());
-            } else if (block instanceof MemberCalldataBlock) {
-                _.eachRight(block.getMembers(), (member: CalldataBlock) => {
-                    blockQueue.pushFront(member);
-                });
-            }
-        }
-
-        console.log(this.root);
-
-        // Fetch values using same technique
-        const valueBufs: Buffer[] = [selectorBuffer];
-        blockQueue.push(this.root);
-        while ((block = blockQueue.pop()) !== undefined) {
-            valueBufs.push(block.toBuffer());
-
-            if (block instanceof DependentCalldataBlock) {
-                blockQueue.push(block.getDependency());
-            } else if (block instanceof MemberCalldataBlock) {
-                _.eachRight(block.getMembers(), (member: CalldataBlock) => {
-                    blockQueue.pushFront(member);
-                });
-            }
-        }*/
-
         const combinedBuffers = Buffer.concat(valueBufs);
         const hexValue = ethUtil.bufferToHex(combinedBuffers);
         return hexValue;
-- 
cgit v1.2.3


From 9b1f56c9687d3fffb2f59fa98d619ead90c1b910 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 12 Nov 2018 17:10:32 -0800
Subject: Decoding works for some basic typs

---
 packages/order-utils/test/abi/calldata.ts       | 102 ++++++++++++++++++++++-
 packages/order-utils/test/abi/data_type.ts      |  43 +++++++++-
 packages/order-utils/test/abi/evm_data_types.ts | 103 +++++++++++++++++++++++-
 packages/order-utils/test/abi_encoder_test.ts   |  40 ++++++---
 4 files changed, 274 insertions(+), 14 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 94f6a5571..0445f68ec 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -164,6 +164,12 @@ class Queue<T> {
     mergeFront(q: Queue<T>) {
         this.store = q.store.concat(this.store);
     }
+    getStore(): T[] {
+        return this.store;
+    }
+    peek(): T | undefined {
+        return this.store.length >= 0 ? this.store[0] : undefined;
+    }
 }
 
 export class Calldata {
@@ -203,7 +209,29 @@ export class Calldata {
         return blockQueue;
     }
 
-    public toHexString(): string {
+    /*
+
+    // Basic optimize method that prunes duplicate branches of the tree
+    // Notes:
+    //      1. Pruning is at the calldata block level, so it is independent of type
+    //      2. 
+    private optimize(blocks: CalldataBlock[]) {
+        // Build hash table of blocks
+        const blockLookupTable: { [key: string]: string } = {};
+        _.each(blocks, (block: CalldataBlock) => {
+            if (blocks instanceof DependentCalldataBlock === false) {
+
+                return;
+            }
+
+            const leavesHash = block.hashLeaves();
+            if (leavesHash in blockLookupTable) {
+
+            }
+        })
+    }*/
+
+    public toHexString(optimize: boolean = false): string {
         let selectorBuffer = ethUtil.toBuffer(this.selector);
         if (this.root === undefined) {
             throw new Error('expected root');
@@ -223,6 +251,8 @@ export class Calldata {
             valueBufs.push(block.toBuffer());
         }
 
+        // if (optimize) this.optimize(valueQueue.getStore());
+
         const combinedBuffers = Buffer.concat(valueBufs);
         const hexValue = ethUtil.bufferToHex(combinedBuffers);
         return hexValue;
@@ -259,4 +289,74 @@ export class Calldata {
         }
         this.sizeInBytes += 8;
     }
+}
+
+export class RawCalldata {
+    private value: Buffer;
+    private offset: number; // tracks current offset into raw calldata; used for parsing
+    private selector: string;
+    private scopes: Queue<number>;
+
+    constructor(value: string | Buffer) {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Expected raw calldata to start with '0x'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
+        this.value = valueBuf.slice(4); // disregard selector
+        this.offset = 0;
+        this.scopes = new Queue<number>();
+        this.scopes.push(0);
+    }
+
+    public popBytes(lengthInBytes: number): Buffer {
+        const value = this.value.slice(this.offset, this.offset + lengthInBytes);
+        this.setOffset(this.offset + lengthInBytes);
+        return value;
+    }
+
+    public popWord(): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(wordInBytes);
+    }
+
+    public popWords(length: number): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(length * wordInBytes);
+    }
+
+    public readBytes(from: number, to: number): Buffer {
+        const value = this.value.slice(from, to);
+        return value;
+    }
+
+    public setOffset(offsetInBytes: number) {
+        this.offset = offsetInBytes;
+        console.log('0'.repeat(100), this.offset);
+    }
+
+    public startScope() {
+        this.scopes.pushFront(this.offset);
+    }
+
+    public endScope() {
+        this.scopes.pop();
+    }
+
+    public getOffset(): number {
+        return this.offset;
+    }
+
+    public toAbsoluteOffset(relativeOffset: number) {
+        const scopeOffset = this.scopes.peek();
+        if (scopeOffset === undefined) {
+            throw new Error(`Tried to access undefined scope.`);
+        }
+        const absoluteOffset = relativeOffset + scopeOffset;
+        return absoluteOffset;
+    }
+
+    public getSelector(): string {
+        return this.selector;
+    }
 }
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 532407f52..af170f7e6 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -1,4 +1,4 @@
-import { Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
+import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
 import { MethodAbi, DataItem } from 'ethereum-types';
 import { BigNumber } from '@0x/utils';
 import ethUtil = require('ethereumjs-util');
@@ -18,6 +18,7 @@ export abstract class DataType {
     }
 
     public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
+    public abstract generateValue(calldata: RawCalldata): any;
     public abstract encode(value: any, calldata: Calldata): void;
     public abstract getSignature(): string;
     public abstract isStatic(): boolean;
@@ -46,12 +47,18 @@ export abstract class PayloadDataType extends DataType {
         // calldata.setRoot(block);
     }
 
+    public generateValue(calldata: RawCalldata): any {
+        const value = this.decodeValue(calldata);
+        return value;
+    }
+
     public isStatic(): boolean {
         // If a payload has a constant size then it's static
         return this.hasConstantSize;
     }
 
     public abstract encodeValue(value: any): Buffer;
+    public abstract decodeValue(calldata: RawCalldata): any;
 }
 
 export abstract class DependentDataType extends DataType {
@@ -81,6 +88,17 @@ export abstract class DependentDataType extends DataType {
         //calldata.setRoot(block);
     }
 
+    public generateValue(calldata: RawCalldata): any {
+        const destinationOffsetBuf = calldata.popWord();
+        const currentOffset = calldata.getOffset();
+        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
+        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
+        calldata.setOffset(destinationOffsetAbsolute);
+        const value = this.dependency.generateValue(calldata);
+        calldata.setOffset(currentOffset);
+        return value;
+    }
+
     public isStatic(): boolean {
         return true;
     }
@@ -179,7 +197,6 @@ export abstract class MemberDataType extends DataType {
             methodBlock.setHeader(lenBuf);
         }
 
-
         const memberBlocks: CalldataBlock[] = [];
         _.each(members, (member: DataType, idx: number) => {
             const block = member.generateCalldataBlock(value[idx], methodBlock);
@@ -220,6 +237,28 @@ export abstract class MemberDataType extends DataType {
         calldata.setRoot(block);
     }
 
+    public generateValue(calldata: RawCalldata): any[] {
+        let members = this.members;
+        if (this.isArray && this.arrayLength === undefined) {
+            const arrayLengthBuf = calldata.popWord();
+            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+            const hexBase = 16;
+            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
+
+            [members,] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+        }
+
+        calldata.startScope();
+        const decodedValue: any[] = [];
+        _.each(members, (member: DataType, idx: number) => {
+            let memberValue = member.generateValue(calldata);
+            decodedValue.push(memberValue);
+        });
+        calldata.endScope();
+
+        return decodedValue;
+    }
+
     protected computeSignatureOfMembers(): string {
         // Compute signature of members
         let signature = `(`;
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index dfa541e80..a05c29b28 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -4,7 +4,7 @@ import { MethodAbi, DataItem } from 'ethereum-types';
 
 import ethUtil = require('ethereumjs-util');
 
-import { Calldata } from './calldata';
+import { Calldata, RawCalldata } from './calldata';
 
 import { BigNumber } from '@0x/utils';
 
@@ -13,6 +13,7 @@ var _ = require('lodash');
 export interface DataTypeStaticInterface {
     matchGrammar: (type: string) => boolean;
     encodeValue: (value: any) => Buffer;
+    //    decodeValue: (value: Buffer) => [any, Buffer];
 }
 
 export class Address extends PayloadDataType {
@@ -38,6 +39,13 @@ export class Address extends PayloadDataType {
         const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
         return encodedValueBuf;
     }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(12);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
 }
 
 export class Bool extends PayloadDataType {
@@ -64,6 +72,17 @@ export class Bool extends PayloadDataType {
         const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
         return encodedValueBuf;
     }
+
+    public decodeValue(calldata: RawCalldata): boolean {
+        const valueBuf = calldata.popWord();
+        const valueHex = ethUtil.bufferToHex(valueBuf);
+        const valueNumber = new BigNumber(valueHex, 16);
+        let value: boolean = (valueNumber.equals(0)) ? false : true;
+        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
+            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
+        }
+        return value;
+    }
 }
 
 abstract class Number extends PayloadDataType {
@@ -126,6 +145,37 @@ abstract class Number extends PayloadDataType {
         return valueBuf;
     }
 
+    public decodeValue(calldata: RawCalldata): BigNumber {
+        const decodedValueBuf = calldata.popWord();
+        const decodedValueHex = ethUtil.bufferToHex(decodedValueBuf);
+        let decodedValue = new BigNumber(decodedValueHex, 16);
+        if (this instanceof Int) {
+            // Check if we're negative
+            const binBase = 2;
+            const decodedValueBin = decodedValue.toString(binBase);
+            if (decodedValueBin[0] === '1') {
+                // Negative
+                // Step 1/3: Invert binary value
+                const bitsInEvmWord = 256;
+                let invertedValueBin = '1'.repeat(bitsInEvmWord - decodedValueBin.length);
+                _.each(decodedValueBin, (bit: string) => {
+                    invertedValueBin += bit === '1' ? '0' : '1';
+                });
+                const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+                // Step 2/3: Add 1 to inverted value
+                // The result is the two's-complement represent of the input value.
+                const positiveDecodedValue = invertedValue.plus(binBase);
+
+                // Step 3/3: Invert positive value
+                const negativeDecodedValue = positiveDecodedValue.times(-1);
+                decodedValue = negativeDecodedValue;
+            }
+        }
+
+        return decodedValue;
+    }
+
     public abstract getMaxValue(): BigNumber;
     public abstract getMinValue(): BigNumber;
 }
@@ -228,6 +278,13 @@ export class Byte extends PayloadDataType {
         return paddedValue;
     }
 
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(0, this.width);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+
     public static matchGrammar(type: string): boolean {
         return this.matcher.test(type);
     }
@@ -262,6 +319,17 @@ export class Bytes extends PayloadDataType {
         return encodedValueBuf;
     }
 
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, 16);
+        const wordsForValue = Math.ceil(length / 32);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const decodedValue = ethUtil.bufferToHex(valueBuf);
+        return decodedValue;
+    }
+
     public getSignature(): string {
         return 'bytes';
     }
@@ -289,6 +357,18 @@ export class SolString extends PayloadDataType {
         return encodedValueBuf;
     }
 
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, 16);
+        const wordsForValue = Math.ceil(length / 32);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        console.log('LENGTH UPINYA === ', length);
+        const value = valueBuf.toString('ascii');
+        return value;
+    }
+
     public getSignature(): string {
         return 'string';
     }
@@ -415,6 +495,27 @@ export class Method extends MemberDataType {
         return calldata.toHexString();
     }
 
+    /*
+    protected decodeValue(value: Buffer): any[] {
+        const selectorBuf = value.slice(4);
+        const selectorHex = ethUtil.bufferToHex(selectorBuf);
+        if (this.selector !== selectorHex) {
+            throw new Error(`Tried to decode calldata with mismatched selector. Expected '${this.selector}', got '${selectorHex}'`);
+        }
+        const remainingValue = value.slice(9);
+        const decodedValue = super.decodeValue(remainingValue);
+        return decodedValue;
+    }*/
+
+    public decode(calldata: string): any[] {
+        const calldata_ = new RawCalldata(calldata);
+        if (this.selector !== calldata_.getSelector()) {
+            throw new Error(`Tried to decode calldata with mismatched selector. Expected '${this.selector}', got '${calldata_.getSelector()}'`);
+        }
+        const value = super.generateValue(calldata_);
+        return value;
+    }
+
     public getSignature(): string {
         return this.methodSignature;
     }
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 0db5f4281..e8ebd7b98 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -310,6 +310,12 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata =
                 '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
 
@@ -327,38 +333,52 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata =
                 '0x7ac2bd96af000000000000000000000000000000000000000000000000000000000000000001020304050607080911121314151617181920212223242526272829303132000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-        });
 
-        it('Yessir', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.simpleAbi);
-            const calldata = method.encode([new BigNumber(5), 'five']);
-            console.log(calldata);
-            expect(true).to.be.true();
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
-        it('Array ABI', async () => {
+        it.only('Array ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
             console.log(method);
-            const calldata = method.encode([['five', 'six', 'seven']]);
+            const args = [['five', 'six', 'seven']];
+            const calldata = method.encode(args);
             console.log(method.getSignature());
             console.log(method.selector);
 
+            /*
             console.log(calldata);
             const expectedCalldata =
                 '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
+            expect(calldata).to.be.equal(expectedCalldata);*/
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Static Tuple', async () => {
             // This is dynamic because it has dynamic members
             const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
-            const calldata = method.encode([[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]]);
+            const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
+            const calldata = method.encode(args);
             console.log(method.getSignature());
             console.log(method.selector);
 
             console.log(calldata);
             const expectedCalldata = '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Dynamic Tuple (Array input)', async () => {
-- 
cgit v1.2.3


From c5d252ba4a79a0f16e053a071b0173a7bd666328 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 12 Nov 2018 17:14:25 -0800
Subject: decoding works for most cases

---
 packages/order-utils/test/abi_encoder_test.ts | 94 +++++++++++++++++++++++++--
 1 file changed, 89 insertions(+), 5 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index e8ebd7b98..631255e68 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -89,9 +89,15 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata = '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
             //const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            /*const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);*/
         });
 
-        it('Crazy ABI #1', async () => {
+        it.only('Crazy ABI #1', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
 
             const args = [
@@ -113,6 +119,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
 
@@ -127,6 +139,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Array of Static Tuples (Array has defined length)', async () => {
@@ -145,6 +163,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Array of Static Tuples (Array has dynamic length)', async () => {
@@ -163,6 +187,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Array of Dynamic Tuples (Array has defined length)', async () => {
@@ -181,6 +211,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
@@ -199,6 +235,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Multidimensional Arrays / Static Members', async () => {
@@ -228,6 +270,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; expect(calldata).to.be.equal(expectedCalldata);
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Multidimensional Arrays / Dynamic Members', async () => {
@@ -257,6 +305,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Fixed Lenfgth Array / Dynamic Members', async () => {
@@ -269,6 +323,12 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata =
                 '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Fixed Lenfgth Array / Dynamic Members', async () => {
@@ -281,6 +341,12 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata =
                 '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Unfixed Length Array / Dynamic Members ABI', async () => {
@@ -292,6 +358,12 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(args));
             const expectedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Unfixed Length Array / Static Members ABI', async () => {
@@ -300,6 +372,12 @@ describe.only('ABI Encoder', () => {
             const calldata = method.encode(args);
             const expectedCalldata = '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
 
@@ -341,7 +419,7 @@ describe.only('ABI Encoder', () => {
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
-        it.only('Array ABI', async () => {
+        it('Array ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
             console.log(method);
             const args = [['five', 'six', 'seven']];
@@ -349,11 +427,10 @@ describe.only('ABI Encoder', () => {
             console.log(method.getSignature());
             console.log(method.selector);
 
-            /*
             console.log(calldata);
             const expectedCalldata =
                 '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);*/
+            expect(calldata).to.be.equal(expectedCalldata);
 
             // Test decoding
             const expectedDecodedValueJson = JSON.stringify(args);
@@ -384,7 +461,8 @@ describe.only('ABI Encoder', () => {
         it('Dynamic Tuple (Array input)', async () => {
             // This is dynamic because it has dynamic members
             const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([[new BigNumber(5), 'five']]);
+            const args = [[new BigNumber(5), 'five']];
+            const calldata = method.encode(args);
             console.log(method.getSignature());
             console.log(method.selector);
 
@@ -392,6 +470,12 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata =
                 '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
         it('Dynamic Tuple (Object input)', async () => {
-- 
cgit v1.2.3


From 2a6b358717e3134aef3ff86cc5343b3b37edee7e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 12 Nov 2018 17:28:46 -0800
Subject: Decoder works for uints with width less than 256

---
 packages/order-utils/test/abi/evm_data_types.ts | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index a05c29b28..abb4fba14 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -146,34 +146,34 @@ abstract class Number extends PayloadDataType {
     }
 
     public decodeValue(calldata: RawCalldata): BigNumber {
-        const decodedValueBuf = calldata.popWord();
-        const decodedValueHex = ethUtil.bufferToHex(decodedValueBuf);
-        let decodedValue = new BigNumber(decodedValueHex, 16);
+        const paddedValueBuf = calldata.popWord();
+        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
+        let value = new BigNumber(paddedValueHex, 16);
         if (this instanceof Int) {
             // Check if we're negative
             const binBase = 2;
-            const decodedValueBin = decodedValue.toString(binBase);
-            if (decodedValueBin[0] === '1') {
+            const paddedValueBin = value.toString(binBase);
+            const valueBin = paddedValueBin.slice(paddedValueBin.length - this.width);
+            if (valueBin[0].startsWith('1')) {
                 // Negative
                 // Step 1/3: Invert binary value
-                const bitsInEvmWord = 256;
-                let invertedValueBin = '1'.repeat(bitsInEvmWord - decodedValueBin.length);
-                _.each(decodedValueBin, (bit: string) => {
+                let invertedValueBin = '';
+                _.each(valueBin, (bit: string) => {
                     invertedValueBin += bit === '1' ? '0' : '1';
                 });
                 const invertedValue = new BigNumber(invertedValueBin, binBase);
 
                 // Step 2/3: Add 1 to inverted value
                 // The result is the two's-complement represent of the input value.
-                const positiveDecodedValue = invertedValue.plus(binBase);
+                const positiveValue = invertedValue.plus(1);
 
                 // Step 3/3: Invert positive value
-                const negativeDecodedValue = positiveDecodedValue.times(-1);
-                decodedValue = negativeDecodedValue;
+                const negativeValue = positiveValue.times(-1);
+                value = negativeValue;
             }
         }
 
-        return decodedValue;
+        return value;
     }
 
     public abstract getMaxValue(): BigNumber;
-- 
cgit v1.2.3


From 52474a0b8edb2f49f850069c1a79dcd9b5d77e9d Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 12 Nov 2018 17:49:52 -0800
Subject: decoding with objects as structs works

---
 packages/order-utils/test/abi/data_type.ts      | 37 ++++++++++++++++---------
 packages/order-utils/test/abi/evm_data_types.ts | 21 ++++----------
 packages/order-utils/test/abi_encoder_test.ts   | 21 ++++++++++----
 3 files changed, 45 insertions(+), 34 deletions(-)

diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index af170f7e6..725d314f3 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -4,7 +4,9 @@ import { BigNumber } from '@0x/utils';
 import ethUtil = require('ethereumjs-util');
 var _ = require('lodash');
 
-
+export interface GenerateValueRules {
+    structsAsObjects: boolean;
+}
 
 export abstract class DataType {
     private dataItem: DataItem;
@@ -18,7 +20,7 @@ export abstract class DataType {
     }
 
     public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
-    public abstract generateValue(calldata: RawCalldata): any;
+    public abstract generateValue(calldata: RawCalldata, rules: GenerateValueRules): any;
     public abstract encode(value: any, calldata: Calldata): void;
     public abstract getSignature(): string;
     public abstract isStatic(): boolean;
@@ -47,7 +49,7 @@ export abstract class PayloadDataType extends DataType {
         // calldata.setRoot(block);
     }
 
-    public generateValue(calldata: RawCalldata): any {
+    public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any {
         const value = this.decodeValue(calldata);
         return value;
     }
@@ -88,13 +90,13 @@ export abstract class DependentDataType extends DataType {
         //calldata.setRoot(block);
     }
 
-    public generateValue(calldata: RawCalldata): any {
+    public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any {
         const destinationOffsetBuf = calldata.popWord();
         const currentOffset = calldata.getOffset();
         const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
         const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
         calldata.setOffset(destinationOffsetAbsolute);
-        const value = this.dependency.generateValue(calldata);
+        const value = this.dependency.generateValue(calldata, rules);
         calldata.setOffset(currentOffset);
         return value;
     }
@@ -237,7 +239,7 @@ export abstract class MemberDataType extends DataType {
         calldata.setRoot(block);
     }
 
-    public generateValue(calldata: RawCalldata): any[] {
+    public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any[] | object {
         let members = this.members;
         if (this.isArray && this.arrayLength === undefined) {
             const arrayLengthBuf = calldata.popWord();
@@ -249,14 +251,23 @@ export abstract class MemberDataType extends DataType {
         }
 
         calldata.startScope();
-        const decodedValue: any[] = [];
-        _.each(members, (member: DataType, idx: number) => {
-            let memberValue = member.generateValue(calldata);
-            decodedValue.push(memberValue);
-        });
+        let value: any[] | object;
+        if (rules.structsAsObjects && !this.isArray) {
+            value = {};
+            _.each(this.memberMap, (idx: number, key: string) => {
+                const member = this.members[idx];
+                let memberValue = member.generateValue(calldata, rules);
+                (value as { [key: string]: any })[key] = memberValue;
+            });
+        } else {
+            value = [];
+            _.each(members, (member: DataType, idx: number) => {
+                let memberValue = member.generateValue(calldata, rules);
+                (value as any[]).push(memberValue);
+            });
+        }
         calldata.endScope();
-
-        return decodedValue;
+        return value;
     }
 
     protected computeSignatureOfMembers(): string {
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index abb4fba14..7b366a985 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -1,4 +1,4 @@
-import { DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+import { GenerateValueRules, DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
 
 import { MethodAbi, DataItem } from 'ethereum-types';
 
@@ -495,24 +495,15 @@ export class Method extends MemberDataType {
         return calldata.toHexString();
     }
 
-    /*
-    protected decodeValue(value: Buffer): any[] {
-        const selectorBuf = value.slice(4);
-        const selectorHex = ethUtil.bufferToHex(selectorBuf);
-        if (this.selector !== selectorHex) {
-            throw new Error(`Tried to decode calldata with mismatched selector. Expected '${this.selector}', got '${selectorHex}'`);
-        }
-        const remainingValue = value.slice(9);
-        const decodedValue = super.decodeValue(remainingValue);
-        return decodedValue;
-    }*/
-
-    public decode(calldata: string): any[] {
+    public decode(calldata: string, decodeStructsAsObjects: boolean = false): any[] | object {
         const calldata_ = new RawCalldata(calldata);
         if (this.selector !== calldata_.getSelector()) {
             throw new Error(`Tried to decode calldata with mismatched selector. Expected '${this.selector}', got '${calldata_.getSelector()}'`);
         }
-        const value = super.generateValue(calldata_);
+        let rules: GenerateValueRules = {
+            structsAsObjects: decodeStructsAsObjects
+        };
+        const value = super.generateValue(calldata_, rules);
         return value;
     }
 
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 631255e68..137850b35 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -26,7 +26,7 @@ const expect = chai.expect;
 describe.only('ABI Encoder', () => {
     describe.only('ABI Tests at Method Level', () => {
 
-        it('Crazy ABI', async () => {
+        it.only('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
@@ -78,7 +78,15 @@ describe.only('ABI Encoder', () => {
             };
             const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
 
-            const args = [someStaticArray, someStaticArrayWithDynamicMembers, someDynamicArrayWithDynamicMembers, some2DArray, someTuple, someTupleWithDynamicTypes, someArrayOfTuplesWithDynamicTypes];
+            const args = {
+                someStaticArray: someStaticArray,
+                someStaticArrayWithDynamicMembers: someStaticArrayWithDynamicMembers,
+                someDynamicArrayWithDynamicMembers: someDynamicArrayWithDynamicMembers,
+                some2DArray: some2DArray,
+                someTuple: someTuple,
+                someTupleWithDynamicTypes: someTupleWithDynamicTypes,
+                someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
+            };
 
             const calldata = method.encode(args);
             console.log(calldata);
@@ -91,13 +99,14 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
 
             // Test decoding
-            /*const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata, true);
             const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);*/
+            console.log(`DECODED`, '*'.repeat(200), '\n', decodedValueJson);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
-        it.only('Crazy ABI #1', async () => {
+        it('Crazy ABI #1', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
 
             const args = [
-- 
cgit v1.2.3


From 7c733662e2669ca6682920f321c81e770605b3d5 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 13 Nov 2018 12:36:14 -0800
Subject: Annotated calldata (draft).

---
 packages/order-utils/test/abi/calldata.ts       | 113 ++++++++++++++++++++----
 packages/order-utils/test/abi/data_type.ts      |  21 +++--
 packages/order-utils/test/abi/evm_data_types.ts |   4 +-
 packages/order-utils/test/abi_encoder_test.ts   |   7 +-
 4 files changed, 118 insertions(+), 27 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 0445f68ec..1173f90cc 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -9,10 +9,12 @@ export abstract class CalldataBlock {
     private headerSizeInBytes: number;
     private bodySizeInBytes: number;
     private relocatable: boolean;
+    private parentName: string;
 
-    constructor(name: string, signature: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
+    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
         this.name = name;
         this.signature = signature;
+        this.parentName = parentName;
         this.offsetInBytes = 0;
         this.headerSizeInBytes = headerSizeInBytes;
         this.bodySizeInBytes = bodySizeInBytes;
@@ -31,6 +33,10 @@ export abstract class CalldataBlock {
         return this.name;
     }
 
+    public getParentName(): string {
+        return this.parentName;
+    }
+
     public getSignature(): string {
         return this.signature;
     }
@@ -65,10 +71,10 @@ export abstract class CalldataBlock {
 export class PayloadCalldataBlock extends CalldataBlock {
     private payload: Buffer;
 
-    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
+    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = payload.byteLength;
-        super(name, signature, /*offsetInBytes,*/ headerSizeInBytes, bodySizeInBytes, relocatable);
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
         this.payload = payload;
     }
 
@@ -82,10 +88,10 @@ export class DependentCalldataBlock extends CalldataBlock {
     private parent: CalldataBlock;
     private dependency: CalldataBlock;
 
-    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
+    constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, /*offsetInBytes,*/ headerSizeInBytes, bodySizeInBytes, relocatable);
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
         this.parent = parent;
         this.dependency = dependency;
     }
@@ -112,8 +118,8 @@ export class MemberCalldataBlock extends CalldataBlock {
     private members: CalldataBlock[];
     private contiguous: boolean;
 
-    constructor(name: string, signature: string, /*offsetInBytes: number,*/ relocatable: boolean, contiguous: boolean) {
-        super(name, signature, /*offsetInBytes,*/ 0, 0, relocatable);
+    constructor(name: string, signature: string, parentName: string, relocatable: boolean, contiguous: boolean) {
+        super(name, signature, parentName, 0, 0, relocatable);
         this.members = [];
         this.header = undefined;
         this.contiguous = contiguous;
@@ -231,33 +237,110 @@ export class Calldata {
         })
     }*/
 
-    public toHexString(optimize: boolean = false): string {
-        let selectorBuffer = ethUtil.toBuffer(this.selector);
+    private generateAnnotatedHexString(): string {
+        let hexValue = `${this.selector}`;
         if (this.root === undefined) {
             throw new Error('expected root');
         }
 
-        const offsetQueue = this.createQueue(this.root);
+        const valueQueue = this.createQueue(this.root);
+
         let block: CalldataBlock | undefined;
         let offset = 0;
-        while ((block = offsetQueue.pop()) !== undefined) {
-            block.setOffset(offset);
-            offset += block.getSizeInBytes();
+        const functionBlock = valueQueue.peek();
+        let functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
+        while ((block = valueQueue.pop()) !== undefined) {
+            // Set f
+
+            // Process each block 1 word at a time
+            const size = block.getSizeInBytes();
+            const name = block.getName();
+            const parentName = block.getParentName();
+            console.log('*'.repeat(50), parentName, ' vs ', name);
+
+            //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
+            //const parentOffset = name.lastIndexOf(parentName);
+            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');//.replace(`${parentName}[`, '[');
+            const signature = block.getSignature();
+
+            // Current offset
+            let offsetStr = '';
+
+            // If this block is empty then it's a newline
+            let value = '';
+            let nameStr = '';
+            let line = '';
+            if (size === 0) {
+                offsetStr = ' '.repeat(10);
+                value = ' '.repeat(74);
+                nameStr = `### ${prettyName.padEnd(80)}`;
+                line = `\n${offsetStr}${value}${nameStr}`;
+            } else {
+                offsetStr = `0x${offset.toString(16)}`.padEnd(10, ' ');
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(0, 32))).padEnd(74);
+                if (block instanceof MemberCalldataBlock) {
+                    nameStr = `### ${prettyName.padEnd(80)}`;
+                    line = `\n${offsetStr}${value}${nameStr}`;
+                } else {
+                    nameStr = `    ${prettyName.padEnd(80)}`;
+                    line = `${offsetStr}${value}${nameStr}`;
+                }
+            }
+
+            for (let j = 32; j < size; j += 32) {
+                offsetStr = `0x${(offset + j).toString(16)}`.padEnd(10, ' ');
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + 32))).padEnd(74);
+                nameStr = ' '.repeat(40);
+
+                line = `${line}\n${offsetStr}${value}${nameStr}`;
+            }
+
+            // Append to hex value
+            hexValue = `${hexValue}\n${line}`;
+            offset += size;
+        }
+
+        return hexValue;
+    }
+
+    private generateCondensedHexString(): string {
+        let selectorBuffer = ethUtil.toBuffer(this.selector);
+        if (this.root === undefined) {
+            throw new Error('expected root');
         }
 
         const valueQueue = this.createQueue(this.root);
         const valueBufs: Buffer[] = [selectorBuffer];
+        let block: CalldataBlock | undefined;
         while ((block = valueQueue.pop()) !== undefined) {
             valueBufs.push(block.toBuffer());
         }
 
-        // if (optimize) this.optimize(valueQueue.getStore());
-
         const combinedBuffers = Buffer.concat(valueBufs);
         const hexValue = ethUtil.bufferToHex(combinedBuffers);
         return hexValue;
     }
 
+    public toHexString(optimize: boolean = false, annotate: boolean = false): string {
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const offsetQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        while ((block = offsetQueue.pop()) !== undefined) {
+            block.setOffset(offset);
+            offset += block.getSizeInBytes();
+        }
+
+
+        // if (optimize) this.optimize(valueQueue.getStore());
+
+        const hexValue = annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
+        return hexValue;
+    }
+
     public getSelectorHex(): string {
         return this.selector;
     }
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 725d314f3..25f792c7a 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -38,9 +38,9 @@ export abstract class PayloadDataType extends DataType {
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
-        // const offsetInBytes = calldata.getSizeInBytes();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
         const relocatable = false;
-        const block = new PayloadCalldataBlock(name, signature, /*offsetInBytes,*/ relocatable, encodedValue);
+        const block = new PayloadCalldataBlock(name, signature, parentName, /*offsetInBytes,*/ relocatable, encodedValue);
         return block;
     }
 
@@ -77,11 +77,12 @@ export abstract class DependentDataType extends DataType {
         if (parentBlock === undefined) {
             throw new Error(`DependentDataType requires a parent block to generate its block`);
         }
-        const dependencyBlock = this.dependency.generateCalldataBlock(value);
+        const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
         const relocatable = false;
-        const block = new DependentCalldataBlock(name, signature, /*offsetInBytes,*/ relocatable, dependencyBlock, parentBlock);
+        const block = new DependentCalldataBlock(name, signature, parentName, relocatable, dependencyBlock, parentBlock);
         return block;
     }
 
@@ -179,7 +180,7 @@ export abstract class MemberDataType extends DataType {
         return [members, memberMap];
     }
 
-    protected generateCalldataBlockFromArray(value: any[]): MemberCalldataBlock {
+    protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
         // Sanity check length
         if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
             throw new Error(
@@ -189,7 +190,8 @@ export abstract class MemberDataType extends DataType {
             );
         }
 
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), this.isStatic(), false);
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
 
         let members = this.members;
         if (this.isArray && this.arrayLength === undefined) {
@@ -208,8 +210,9 @@ export abstract class MemberDataType extends DataType {
         return methodBlock;
     }
 
-    protected generateCalldataBlockFromObject(obj: object): MemberCalldataBlock {
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), this.isStatic(), false);
+    protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
         const memberBlocks: CalldataBlock[] = [];
         let childMap = _.cloneDeep(this.memberMap);
         _.forOwn(obj, (value: any, key: string) => {
@@ -230,7 +233,7 @@ export abstract class MemberDataType extends DataType {
     }
 
     public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value) : this.generateCalldataBlockFromObject(value);
+        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value, parentBlock) : this.generateCalldataBlockFromObject(value, parentBlock);
         return block;
     }
 
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index 7b366a985..ea401247b 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -489,10 +489,10 @@ export class Method extends MemberDataType {
         return selector;
     }
 
-    public encode(value: any[] | object, calldata = new Calldata()): string {
+    public encode(value: any[] | object, calldata = new Calldata(), annotate: boolean = false): string {
         calldata.setSelector(this.methodSelector);
         super.encode(value, calldata);
-        return calldata.toHexString();
+        return calldata.toHexString(false, annotate);
     }
 
     public decode(calldata: string, decodeStructsAsObjects: boolean = false): any[] | object {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 137850b35..8b836f77f 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -17,6 +17,7 @@ import { assert } from '@0x/order-utils/src/assert';
 import * as AbiEncoder from './abi/abi_encoder';
 
 import * as AbiSamples from './abi_samples';
+import { Calldata } from './abi/calldata';
 
 AbiEncoder.DataTypeFactory.setImpl(new AbiEncoder.EvmDataTypeFactoryImpl());
 
@@ -88,8 +89,12 @@ describe.only('ABI Encoder', () => {
                 someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
             };
 
-            const calldata = method.encode(args);
+            const calldata = method.encode(args, new Calldata(), true);
             console.log(calldata);
+
+
+            throw new Error(`done`);
+
             console.log('*'.repeat(40));
             console.log(JSON.stringify(args));
             console.log(method.getSignature());
-- 
cgit v1.2.3


From 457cb1dc843511d6e987b0ffce0f985d4e97c968 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 13 Nov 2018 15:55:07 -0800
Subject: optimizer works for basic case

---
 packages/order-utils/test/abi/calldata.ts       | 98 +++++++++++++++++++++++--
 packages/order-utils/test/abi/evm_data_types.ts |  4 +-
 packages/order-utils/test/abi_encoder_test.ts   | 16 +++-
 3 files changed, 109 insertions(+), 9 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 1173f90cc..ab42b7d73 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -29,6 +29,10 @@ export abstract class CalldataBlock {
         this.bodySizeInBytes = bodySizeInBytes;
     }
 
+    protected setName(name: string) {
+        this.name = name;
+    }
+
     public getName(): string {
         return this.name;
     }
@@ -65,7 +69,14 @@ export abstract class CalldataBlock {
         this.offsetInBytes = offsetInBytes;
     }
 
+    public computeHash(): Buffer {
+        const rawData = this.getRawData();
+        const hash = ethUtil.sha3(rawData);
+        return hash;
+    }
+
     public abstract toBuffer(): Buffer;
+    public abstract getRawData(): Buffer;
 }
 
 export class PayloadCalldataBlock extends CalldataBlock {
@@ -81,12 +92,19 @@ export class PayloadCalldataBlock extends CalldataBlock {
     public toBuffer(): Buffer {
         return this.payload;
     }
+
+    public getRawData(): Buffer {
+        return this.payload;
+    }
 }
 
 export class DependentCalldataBlock extends CalldataBlock {
     public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    public static RAW_DATA_START = new Buffer('<');
+    public static RAW_DATA_END = new Buffer('>');
     private parent: CalldataBlock;
     private dependency: CalldataBlock;
+    private aliasFor: CalldataBlock | undefined;
 
     constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
         const headerSizeInBytes = 0;
@@ -94,13 +112,14 @@ export class DependentCalldataBlock extends CalldataBlock {
         super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
         this.parent = parent;
         this.dependency = dependency;
+        this.aliasFor = undefined;
     }
 
     public toBuffer(): Buffer {
-        const dependencyOffset = this.dependency.getOffsetInBytes();
+        const destinationOffset = (this.aliasFor !== undefined) ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
         const parentOffset = this.parent.getOffsetInBytes();
         const parentHeaderSize = this.parent.getHeaderSizeInBytes();
-        const pointer: number = dependencyOffset - (parentOffset + parentHeaderSize);
+        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
         const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
         const evmWordWidthInBytes = 32;
         const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
@@ -110,6 +129,25 @@ export class DependentCalldataBlock extends CalldataBlock {
     public getDependency(): CalldataBlock {
         return this.dependency;
     }
+
+    public setAlias(block: CalldataBlock) {
+        this.aliasFor = block;
+        this.setName(`${this.getName()} (alias for ${block.getName()})`);
+    }
+
+    public getAlias(): CalldataBlock | undefined {
+        return this.aliasFor;
+    }
+
+    public getRawData(): Buffer {
+        const dependencyRawData = this.dependency.getRawData();
+        const rawDataComponents: Buffer[] = [];
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
+        rawDataComponents.push(dependencyRawData);
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
 }
 
 export class MemberCalldataBlock extends CalldataBlock {
@@ -125,6 +163,20 @@ export class MemberCalldataBlock extends CalldataBlock {
         this.contiguous = contiguous;
     }
 
+    public getRawData(): Buffer {
+        const rawDataComponents: Buffer[] = [];
+        if (this.header !== undefined) {
+            rawDataComponents.push(this.header);
+        }
+        _.each(this.members, (member: CalldataBlock) => {
+            const memberBuffer = member.getRawData();
+            rawDataComponents.push(memberBuffer);
+        });
+
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+
     public setMembers(members: CalldataBlock[]) {
         let bodySizeInBytes = 0;
         _.each(members, (member: CalldataBlock) => {
@@ -201,8 +253,8 @@ export class Calldata {
 
         // Children
         _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof DependentCalldataBlock) {
-                const dependency = member.getDependency();
+            if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
+                let dependency = member.getDependency();
                 if (dependency instanceof MemberCalldataBlock) {
                     blockQueue.merge(this.createQueue(dependency));
                 } else {
@@ -321,6 +373,41 @@ export class Calldata {
         return hexValue;
     }
 
+    public optimize() {
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const subtreesByHash: { [key: string]: DependentCalldataBlock[] } = {};
+
+        // 1. Create a queue of subtrees by hash
+        // Note that they are ordered the same as 
+        const subtreeQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        while ((block = subtreeQueue.pop()) !== undefined) {
+            console.log(block.getName());
+
+            if (block instanceof DependentCalldataBlock === false) continue;
+            const blockHashBuf = block.computeHash();
+            const blockHashHex = ethUtil.bufferToHex(blockHashBuf);
+            if (blockHashHex in subtreesByHash === false) {
+                subtreesByHash[blockHashHex] = [block as DependentCalldataBlock];
+            } else {
+                subtreesByHash[blockHashHex].push(block as DependentCalldataBlock);
+            }
+        }
+
+        // Iterate through trees that have the same hash and 
+        _.each(subtreesByHash, (subtrees: DependentCalldataBlock[], hash: string) => {
+            if (subtrees.length === 1) return; // No optimization
+            // Optimize
+            const lastSubtree = subtrees[subtrees.length - 1];
+            for (let i = 0; i < subtrees.length - 1; ++i) {
+                subtrees[i].setAlias(lastSubtree);
+            }
+        });
+    }
+
     public toHexString(optimize: boolean = false, annotate: boolean = false): string {
         if (this.root === undefined) {
             throw new Error('expected root');
@@ -334,8 +421,7 @@ export class Calldata {
             offset += block.getSizeInBytes();
         }
 
-
-        // if (optimize) this.optimize(valueQueue.getStore());
+        if (optimize) this.optimize();
 
         const hexValue = annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
         return hexValue;
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index ea401247b..a24046664 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -489,10 +489,10 @@ export class Method extends MemberDataType {
         return selector;
     }
 
-    public encode(value: any[] | object, calldata = new Calldata(), annotate: boolean = false): string {
+    public encode(value: any[] | object, calldata = new Calldata(), annotate: boolean = false, optimize: boolean = false): string {
         calldata.setSelector(this.methodSelector);
         super.encode(value, calldata);
-        return calldata.toHexString(false, annotate);
+        return calldata.toHexString(optimize, annotate);
     }
 
     public decode(calldata: string, decodeStructsAsObjects: boolean = false): any[] | object {
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 8b836f77f..5ef4203b7 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -27,7 +27,21 @@ const expect = chai.expect;
 describe.only('ABI Encoder', () => {
     describe.only('ABI Tests at Method Level', () => {
 
-        it.only('Crazy ABI', async () => {
+        it.only('Optimizer', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
+            const strings = [
+                "Test String",
+                "Test String 2",
+                "Test String",
+                "Test String 2",
+            ];
+            const args = [strings];
+
+            const optimizedCalldata = method.encode(args, new Calldata(), true, true);
+            console.log(optimizedCalldata);
+        });
+
+        it('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
 
-- 
cgit v1.2.3


From 27cb966991c9408025106624f36927548b9e873c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 13 Nov 2018 16:17:24 -0800
Subject: Alias now points to dependency, not pointer

---
 packages/order-utils/test/abi/calldata.ts     |  6 +++---
 packages/order-utils/test/abi_encoder_test.ts | 25 ++++++++++++++++++++++++-
 packages/order-utils/test/abi_samples.ts      | 19 +++++++++++++++++++
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index ab42b7d73..04bea9628 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -403,7 +403,7 @@ export class Calldata {
             // Optimize
             const lastSubtree = subtrees[subtrees.length - 1];
             for (let i = 0; i < subtrees.length - 1; ++i) {
-                subtrees[i].setAlias(lastSubtree);
+                subtrees[i].setAlias(lastSubtree.getDependency());
             }
         });
     }
@@ -413,6 +413,8 @@ export class Calldata {
             throw new Error('expected root');
         }
 
+        if (optimize) this.optimize();
+
         const offsetQueue = this.createQueue(this.root);
         let block: CalldataBlock | undefined;
         let offset = 0;
@@ -421,8 +423,6 @@ export class Calldata {
             offset += block.getSizeInBytes();
         }
 
-        if (optimize) this.optimize();
-
         const hexValue = annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
         return hexValue;
     }
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 5ef4203b7..661fb62a6 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -27,7 +27,7 @@ const expect = chai.expect;
 describe.only('ABI Encoder', () => {
     describe.only('ABI Tests at Method Level', () => {
 
-        it.only('Optimizer', async () => {
+        it('Optimizer #1', async () => {
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
             const strings = [
                 "Test String",
@@ -41,6 +41,29 @@ describe.only('ABI Encoder', () => {
             console.log(optimizedCalldata);
         });
 
+        it.only('Optimizer #2', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
+            const stringArray = [
+                "Test String",
+                "Test String",
+                "Test String",
+                "Test String",
+            ];
+            const string = 'Test String';
+            const args = [stringArray, string];
+
+
+            const TEST = method.encode(args, new Calldata(), true, true);
+            console.log(TEST);
+
+            const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+
+            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const decodedArgs = method.decode(optimizedCalldata);
+            console.log(JSON.stringify(decodedArgs));
+            //expect(decodedArgs).to.be.equal(args);
+        });
+
         it('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index 3f7b1a927..fa20c38f0 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -34,6 +34,25 @@ export const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
+export const optimizerAbi2 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'stringArray',
+            type: 'string[]',
+        },
+        {
+            name: 'string',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const typesWithDefaultWidthsAbi = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From b71577cc52d7f933ee7e5dc50e5b61457f04e3f4 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 13 Nov 2018 17:06:41 -0800
Subject: More robust implementation for optimizer

---
 packages/order-utils/test/abi/calldata.ts | 41 +++++++++++++++++--------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 04bea9628..754d8f823 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -216,6 +216,11 @@ class Queue<T> {
     pop(): T | undefined {
         return this.store.shift();
     }
+    popBack(): T | undefined {
+        if (this.store.length === 0) return undefined;
+        const backElement = this.store.splice(-1, 1)[0];
+        return backElement;
+    }
     merge(q: Queue<T>) {
         this.store = this.store.concat(q.store);
     }
@@ -378,34 +383,34 @@ export class Calldata {
             throw new Error('expected root');
         }
 
-        const subtreesByHash: { [key: string]: DependentCalldataBlock[] } = {};
+        const blocksByHash: { [key: string]: CalldataBlock } = {};
 
         // 1. Create a queue of subtrees by hash
         // Note that they are ordered the same as 
         const subtreeQueue = this.createQueue(this.root);
         let block: CalldataBlock | undefined;
-        while ((block = subtreeQueue.pop()) !== undefined) {
+        console.log('*'.repeat(100), ' OPTIMIZING ', '*'.repeat(100));
+        while ((block = subtreeQueue.popBack()) !== undefined) {
             console.log(block.getName());
+            if (block instanceof DependentCalldataBlock) {
+                const blockHashBuf = block.getDependency().computeHash();
+                const blockHash = ethUtil.bufferToHex(blockHashBuf);
+                if (blockHash in blocksByHash) {
+                    const blockWithSameHash = blocksByHash[blockHash];
+                    if (blockWithSameHash !== block.getDependency()) {
+                        block.setAlias(blockWithSameHash);
+                    }
+                }
+                continue;
+            }
 
-            if (block instanceof DependentCalldataBlock === false) continue;
             const blockHashBuf = block.computeHash();
-            const blockHashHex = ethUtil.bufferToHex(blockHashBuf);
-            if (blockHashHex in subtreesByHash === false) {
-                subtreesByHash[blockHashHex] = [block as DependentCalldataBlock];
-            } else {
-                subtreesByHash[blockHashHex].push(block as DependentCalldataBlock);
+            const blockHash = ethUtil.bufferToHex(blockHashBuf);
+            if (blockHash in blocksByHash === false) {
+                blocksByHash[blockHash] = block;
             }
         }
-
-        // Iterate through trees that have the same hash and 
-        _.each(subtreesByHash, (subtrees: DependentCalldataBlock[], hash: string) => {
-            if (subtrees.length === 1) return; // No optimization
-            // Optimize
-            const lastSubtree = subtrees[subtrees.length - 1];
-            for (let i = 0; i < subtrees.length - 1; ++i) {
-                subtrees[i].setAlias(lastSubtree.getDependency());
-            }
-        });
+        console.log('*'.repeat(100), ' FINISHED OPTIMIZING ', '*'.repeat(100));
     }
 
     public toHexString(optimize: boolean = false, annotate: boolean = false): string {
-- 
cgit v1.2.3


From 93e967c3b356f0081254946bbf8d6875fc791a09 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 13 Nov 2018 17:40:14 -0800
Subject: Some tests

---
 packages/order-utils/test/abi_encoder_test.ts | 57 ++++++++++++++++++++++++++-
 packages/order-utils/test/abi_samples.ts      | 50 +++++++++++++++++++++++
 2 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 661fb62a6..78e28015d 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -41,7 +41,7 @@ describe.only('ABI Encoder', () => {
             console.log(optimizedCalldata);
         });
 
-        it.only('Optimizer #2', async () => {
+        it('Optimizer #2', async () => {
             const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
             const stringArray = [
                 "Test String",
@@ -60,8 +60,61 @@ describe.only('ABI Encoder', () => {
 
             console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
             const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
             console.log(JSON.stringify(decodedArgs));
-            //expect(decodedArgs).to.be.equal(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+
+
+        it('Optimizer #3 (tuple should point to array)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi3);
+            const uint8Array = [
+                new BigNumber(100),
+                new BigNumber(150),
+                new BigNumber(200),
+                new BigNumber(225),
+            ];
+            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
+            const args = [uint8Array, uintTupleArray];
+
+
+            const TEST = method.encode(args, new Calldata(), true, true);
+            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
+
+            const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+
+            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            console.log(JSON.stringify(decodedArgs));
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+
+        it.only('Optimizer #4 (Expect no optimization)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
+            const uint8Array = [
+                new BigNumber(100),
+                new BigNumber(150),
+                new BigNumber(200),
+                new BigNumber(225),
+            ];
+            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
+            const args = [uint8Array, uintTupleArray];
+
+
+            const TEST = method.encode(args, new Calldata(), true, true);
+            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
+
+            const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+
+            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            console.log(JSON.stringify(decodedArgs));
+            expect(decodedArgsJson).to.be.equal(argsJson);
         });
 
         it('Crazy ABI', async () => {
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
index fa20c38f0..5e8268f1a 100644
--- a/packages/order-utils/test/abi_samples.ts
+++ b/packages/order-utils/test/abi_samples.ts
@@ -53,6 +53,56 @@ export const optimizerAbi2 = {
     type: 'function',
 } as MethodAbi;
 
+export const optimizerAbi3 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'uint8Array',
+            type: 'uint8[]',
+        },
+        {
+            components: [
+                {
+                    name: 'uint',
+                    type: 'uint',
+                },
+            ],
+            name: 'uintTuple',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const optimizerAbi4 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'uint8Array',
+            type: 'uint8[4]',
+        },
+        {
+            components: [
+                {
+                    name: 'uint',
+                    type: 'uint',
+                },
+            ],
+            name: 'uintTuple',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const typesWithDefaultWidthsAbi = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From 2d2255e9af42f6441ee620c4aa74bd1981dfe03a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 13:51:08 -0800
Subject: Cleaner interface for encoding/decoding. Moved encode/decode
 parameters into a struct.

---
 packages/order-utils/test/abi/calldata.ts       | 43 ++++++++--------------
 packages/order-utils/test/abi/data_type.ts      | 49 +++++++++++++------------
 packages/order-utils/test/abi/evm_data_types.ts | 25 ++++++-------
 packages/order-utils/test/abi_encoder_test.ts   | 25 ++++++-------
 4 files changed, 63 insertions(+), 79 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 754d8f823..7eb4e0026 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -2,6 +2,15 @@ import ethUtil = require('ethereumjs-util');
 import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
 var _ = require('lodash');
 
+export interface DecodingRules {
+    structsAsObjects: boolean;
+}
+
+export interface EncodingRules {
+    optimize?: boolean;
+    annotate?: boolean;
+}
+
 export abstract class CalldataBlock {
     private name: string;
     private signature: string;
@@ -237,11 +246,13 @@ class Queue<T> {
 
 export class Calldata {
     private selector: string;
+    private rules: EncodingRules;
     private sizeInBytes: number;
     private root: MemberCalldataBlock | undefined;
 
-    constructor() {
-        this.selector = '0x';
+    constructor(rules: EncodingRules) {
+        this.selector = '';
+        this.rules = rules;
         this.sizeInBytes = 0;
         this.root = undefined;
     }
@@ -272,28 +283,6 @@ export class Calldata {
         return blockQueue;
     }
 
-    /*
-
-    // Basic optimize method that prunes duplicate branches of the tree
-    // Notes:
-    //      1. Pruning is at the calldata block level, so it is independent of type
-    //      2. 
-    private optimize(blocks: CalldataBlock[]) {
-        // Build hash table of blocks
-        const blockLookupTable: { [key: string]: string } = {};
-        _.each(blocks, (block: CalldataBlock) => {
-            if (blocks instanceof DependentCalldataBlock === false) {
-
-                return;
-            }
-
-            const leavesHash = block.hashLeaves();
-            if (leavesHash in blockLookupTable) {
-
-            }
-        })
-    }*/
-
     private generateAnnotatedHexString(): string {
         let hexValue = `${this.selector}`;
         if (this.root === undefined) {
@@ -413,12 +402,12 @@ export class Calldata {
         console.log('*'.repeat(100), ' FINISHED OPTIMIZING ', '*'.repeat(100));
     }
 
-    public toHexString(optimize: boolean = false, annotate: boolean = false): string {
+    public toHexString(): string {
         if (this.root === undefined) {
             throw new Error('expected root');
         }
 
-        if (optimize) this.optimize();
+        if (this.rules.optimize) this.optimize();
 
         const offsetQueue = this.createQueue(this.root);
         let block: CalldataBlock | undefined;
@@ -428,7 +417,7 @@ export class Calldata {
             offset += block.getSizeInBytes();
         }
 
-        const hexValue = annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
+        const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
         return hexValue;
     }
 
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 25f792c7a..6ad0b2736 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -1,14 +1,14 @@
 import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
 import { MethodAbi, DataItem } from 'ethereum-types';
+import { DecodingRules, EncodingRules } from './calldata';
 import { BigNumber } from '@0x/utils';
 import ethUtil = require('ethereumjs-util');
 var _ = require('lodash');
 
-export interface GenerateValueRules {
-    structsAsObjects: boolean;
-}
-
 export abstract class DataType {
+    private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
+    private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
+
     private dataItem: DataItem;
 
     constructor(dataItem: DataItem) {
@@ -19,9 +19,25 @@ export abstract class DataType {
         return this.dataItem;
     }
 
+    public encode(value: any, rules?: EncodingRules, selector?: string): string {
+        const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
+        const calldata = new Calldata(rules_);
+        if (selector) calldata.setSelector(selector);
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
+        const calldataHex = calldata.toHexString();
+        return calldataHex;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules): any {
+        const rawCalldata = new RawCalldata(calldata);
+        const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
+        const value = this.generateValue(rawCalldata, rules_);
+        return value;
+    }
+
     public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
-    public abstract generateValue(calldata: RawCalldata, rules: GenerateValueRules): any;
-    public abstract encode(value: any, calldata: Calldata): void;
+    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
     public abstract getSignature(): string;
     public abstract isStatic(): boolean;
 }
@@ -44,12 +60,7 @@ export abstract class PayloadDataType extends DataType {
         return block;
     }
 
-    public encode(value: any, calldata: Calldata): void {
-        const block = this.generateCalldataBlock(value);
-        // calldata.setRoot(block);
-    }
-
-    public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any {
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
         const value = this.decodeValue(calldata);
         return value;
     }
@@ -86,12 +97,7 @@ export abstract class DependentDataType extends DataType {
         return block;
     }
 
-    public encode(value: any, calldata: Calldata = new Calldata()): void {
-        const block = this.generateCalldataBlock(value);
-        //calldata.setRoot(block);
-    }
-
-    public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any {
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
         const destinationOffsetBuf = calldata.popWord();
         const currentOffset = calldata.getOffset();
         const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
@@ -237,12 +243,7 @@ export abstract class MemberDataType extends DataType {
         return block;
     }
 
-    public encode(value: any, calldata: Calldata = new Calldata()): void {
-        const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block);
-    }
-
-    public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any[] | object {
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
         let members = this.members;
         if (this.isArray && this.arrayLength === undefined) {
             const arrayLengthBuf = calldata.popWord();
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index a24046664..9504b1a10 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -1,4 +1,6 @@
-import { GenerateValueRules, DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+import { DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+
+import { DecodingRules, EncodingRules } from './calldata';
 
 import { MethodAbi, DataItem } from 'ethereum-types';
 
@@ -13,7 +15,7 @@ var _ = require('lodash');
 export interface DataTypeStaticInterface {
     matchGrammar: (type: string) => boolean;
     encodeValue: (value: any) => Buffer;
-    //    decodeValue: (value: Buffer) => [any, Buffer];
+    decodeValue: (rawCalldata: RawCalldata) => any;
 }
 
 export class Address extends PayloadDataType {
@@ -489,21 +491,16 @@ export class Method extends MemberDataType {
         return selector;
     }
 
-    public encode(value: any[] | object, calldata = new Calldata(), annotate: boolean = false, optimize: boolean = false): string {
-        calldata.setSelector(this.methodSelector);
-        super.encode(value, calldata);
-        return calldata.toHexString(optimize, annotate);
+    public encode(value: any, rules?: EncodingRules): string {
+        const calldata = super.encode(value, rules, this.selector);
+        return calldata;
     }
 
-    public decode(calldata: string, decodeStructsAsObjects: boolean = false): any[] | object {
-        const calldata_ = new RawCalldata(calldata);
-        if (this.selector !== calldata_.getSelector()) {
-            throw new Error(`Tried to decode calldata with mismatched selector. Expected '${this.selector}', got '${calldata_.getSelector()}'`);
+    public decode(calldata: string, rules?: DecodingRules): any[] | object {
+        if (!calldata.startsWith(this.selector)) {
+            throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
         }
-        let rules: GenerateValueRules = {
-            structsAsObjects: decodeStructsAsObjects
-        };
-        const value = super.generateValue(calldata_, rules);
+        const value = super.decode(calldata, rules);
         return value;
     }
 
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 78e28015d..52b6bc067 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -27,7 +27,7 @@ const expect = chai.expect;
 describe.only('ABI Encoder', () => {
     describe.only('ABI Tests at Method Level', () => {
 
-        it('Optimizer #1', async () => {
+        it('Should reuse duplicated strings in string array', async () => {
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
             const strings = [
                 "Test String",
@@ -37,7 +37,7 @@ describe.only('ABI Encoder', () => {
             ];
             const args = [strings];
 
-            const optimizedCalldata = method.encode(args, new Calldata(), true, true);
+            const optimizedCalldata = method.encode(args, { optimize: true, annotate: true });
             console.log(optimizedCalldata);
         });
 
@@ -53,10 +53,10 @@ describe.only('ABI Encoder', () => {
             const args = [stringArray, string];
 
 
-            const TEST = method.encode(args, new Calldata(), true, true);
+            const TEST = method.encode(args, { optimize: true, annotate: true });
             console.log(TEST);
 
-            const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+            const optimizedCalldata = method.encode(args, { optimize: true });
 
             console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
             const decodedArgs = method.decode(optimizedCalldata);
@@ -79,10 +79,10 @@ describe.only('ABI Encoder', () => {
             const args = [uint8Array, uintTupleArray];
 
 
-            const TEST = method.encode(args, new Calldata(), true, true);
+            const TEST = method.encode(args, { optimize: true, annotate: true });
             console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
 
-            const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+            const optimizedCalldata = method.encode(args, { optimize: true });
 
             console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
             const decodedArgs = method.decode(optimizedCalldata);
@@ -92,7 +92,7 @@ describe.only('ABI Encoder', () => {
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
 
-        it.only('Optimizer #4 (Expect no optimization)', async () => {
+        it('Optimizer #4 (Expect no optimization)', async () => {
             const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
             const uint8Array = [
                 new BigNumber(100),
@@ -104,10 +104,10 @@ describe.only('ABI Encoder', () => {
             const args = [uint8Array, uintTupleArray];
 
 
-            const TEST = method.encode(args, new Calldata(), true, true);
+            const TEST = method.encode(args, { optimize: true, annotate: true });
             console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
 
-            const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+            const optimizedCalldata = method.encode(args, { optimize: true });
 
             console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
             const decodedArgs = method.decode(optimizedCalldata);
@@ -179,12 +179,9 @@ describe.only('ABI Encoder', () => {
                 someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
             };
 
-            const calldata = method.encode(args, new Calldata(), true);
+            const calldata = method.encode(args);
             console.log(calldata);
 
-
-            throw new Error(`done`);
-
             console.log('*'.repeat(40));
             console.log(JSON.stringify(args));
             console.log(method.getSignature());
@@ -195,7 +192,7 @@ describe.only('ABI Encoder', () => {
 
             // Test decoding
             const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata, true);
+            const decodedValue = method.decode(calldata, { structsAsObjects: true });
             const decodedValueJson = JSON.stringify(decodedValue);
             console.log(`DECODED`, '*'.repeat(200), '\n', decodedValueJson);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-- 
cgit v1.2.3


From 063871e549483ba36e5ee2317249eb6dccda24a4 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 13:53:15 -0800
Subject: removed old log messages

---
 packages/order-utils/test/abi/calldata.ts       | 5 -----
 packages/order-utils/test/abi/data_type.ts      | 1 -
 packages/order-utils/test/abi/evm_data_types.ts | 5 -----
 3 files changed, 11 deletions(-)

diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 7eb4e0026..32278e5c5 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -302,7 +302,6 @@ export class Calldata {
             const size = block.getSizeInBytes();
             const name = block.getName();
             const parentName = block.getParentName();
-            console.log('*'.repeat(50), parentName, ' vs ', name);
 
             //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
             //const parentOffset = name.lastIndexOf(parentName);
@@ -378,9 +377,7 @@ export class Calldata {
         // Note that they are ordered the same as 
         const subtreeQueue = this.createQueue(this.root);
         let block: CalldataBlock | undefined;
-        console.log('*'.repeat(100), ' OPTIMIZING ', '*'.repeat(100));
         while ((block = subtreeQueue.popBack()) !== undefined) {
-            console.log(block.getName());
             if (block instanceof DependentCalldataBlock) {
                 const blockHashBuf = block.getDependency().computeHash();
                 const blockHash = ethUtil.bufferToHex(blockHashBuf);
@@ -399,7 +396,6 @@ export class Calldata {
                 blocksByHash[blockHash] = block;
             }
         }
-        console.log('*'.repeat(100), ' FINISHED OPTIMIZING ', '*'.repeat(100));
     }
 
     public toHexString(): string {
@@ -495,7 +491,6 @@ export class RawCalldata {
 
     public setOffset(offsetInBytes: number) {
         this.offset = offsetInBytes;
-        console.log('0'.repeat(100), this.offset);
     }
 
     public startScope() {
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 6ad0b2736..7884cf3cf 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -165,7 +165,6 @@ export abstract class MemberDataType extends DataType {
     }
 
     private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
-        console.log('!'.repeat(30), dataItem);
         let members: DataType[] = [];
         let memberMap: MemberMap = {};
         const range = _.range(length);
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index 9504b1a10..aff4bc991 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -107,7 +107,6 @@ abstract class Number extends PayloadDataType {
     }
 
     public encodeValue(value: BigNumber): Buffer {
-        console.log(value);
         if (value.greaterThan(this.getMaxValue())) {
             throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
         } else if (value.lessThan(this.getMinValue())) {
@@ -366,7 +365,6 @@ export class SolString extends PayloadDataType {
         const wordsForValue = Math.ceil(length / 32);
         const paddedValueBuf = calldata.popWords(wordsForValue);
         const valueBuf = paddedValueBuf.slice(0, length);
-        console.log('LENGTH UPINYA === ', length);
         const value = valueBuf.toString('ascii');
         return value;
     }
@@ -397,7 +395,6 @@ export class Tuple extends MemberDataType {
     private tupleSignature: string;
 
     constructor(dataItem: DataItem) {
-        console.log(dataItem);
         super(dataItem);
         if (!Tuple.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
@@ -516,8 +513,6 @@ export class Method extends MemberDataType {
 export class EvmDataTypeFactoryImpl implements DataTypeFactoryImpl {
 
     public mapDataItemToDataType(dataItem: DataItem): DataType {
-        console.log(`Type: ${dataItem.type}`);
-
         if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
         if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
         if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-- 
cgit v1.2.3


From 3ae434c31e720cb1caf65d776b75524dab388a2f Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 14:27:33 -0800
Subject: Adding optimizer tests

---
 packages/order-utils/test/abi_encoder_test.ts | 36 +++++++++++++++++++--------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 52b6bc067..8ae23a222 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -25,6 +25,10 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
+    describe.only('Optimizer', () => {
+
+    });
+
     describe.only('ABI Tests at Method Level', () => {
 
         it('Should reuse duplicated strings in string array', async () => {
@@ -37,33 +41,45 @@ describe.only('ABI Encoder', () => {
             ];
             const args = [strings];
 
-            const optimizedCalldata = method.encode(args, { optimize: true, annotate: true });
-            console.log(optimizedCalldata);
+            // Verify optimized calldata is expected
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+
+            // Verify args decode properly
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
         });
 
-        it('Optimizer #2', async () => {
+        it.only('Should point array elements to a duplicated value from another parameter', async () => {
             const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
             const stringArray = [
                 "Test String",
                 "Test String",
                 "Test String",
-                "Test String",
+                "Test String 2",
             ];
             const string = 'Test String';
             const args = [stringArray, string];
 
-
-            const TEST = method.encode(args, { optimize: true, annotate: true });
-            console.log(TEST);
-
+            // Verify optimized calldata is expected
             const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata = '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
 
-            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            // Verify args decode properly
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
-            console.log(JSON.stringify(decodedArgs));
             expect(decodedArgsJson).to.be.equal(argsJson);
+
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
         });
 
 
-- 
cgit v1.2.3


From 1f22ce60610617b8176be0f49588067b809907cb Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 14:46:12 -0800
Subject: Removed config.ts

---
 packages/order-utils/test/abi/abi_encoder.ts    |  1 -
 packages/order-utils/test/abi/config.ts         |  4 --
 packages/order-utils/test/abi/data_type.ts      | 72 +++++++------------------
 packages/order-utils/test/abi/evm_data_types.ts | 36 ++++++++-----
 packages/order-utils/test/abi_encoder_test.ts   |  4 +-
 5 files changed, 44 insertions(+), 73 deletions(-)
 delete mode 100644 packages/order-utils/test/abi/config.ts

diff --git a/packages/order-utils/test/abi/abi_encoder.ts b/packages/order-utils/test/abi/abi_encoder.ts
index ddcfb1fd1..4f4906550 100644
--- a/packages/order-utils/test/abi/abi_encoder.ts
+++ b/packages/order-utils/test/abi/abi_encoder.ts
@@ -1,4 +1,3 @@
-export * from './config';
 export * from './calldata';
 export * from './data_type';
 export * from './evm_data_types';
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/config.ts b/packages/order-utils/test/abi/config.ts
deleted file mode 100644
index 015cee59a..000000000
--- a/packages/order-utils/test/abi/config.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { DataTypeFactory } from './data_type';
-import { EvmDataTypeFactoryImpl } from './evm_data_types';
-
-DataTypeFactory.setImpl(new EvmDataTypeFactoryImpl());
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 7884cf3cf..4c4537a69 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -5,20 +5,31 @@ import { BigNumber } from '@0x/utils';
 import ethUtil = require('ethereumjs-util');
 var _ = require('lodash');
 
+export interface DataTypeFactory {
+    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
+    mapDataItemToDataType: (dataItem: DataItem) => DataType;
+}
+
 export abstract class DataType {
     private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
     private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
 
     private dataItem: DataItem;
+    private factory: DataTypeFactory;
 
-    constructor(dataItem: DataItem) {
+    constructor(dataItem: DataItem, factory: DataTypeFactory) {
         this.dataItem = dataItem;
+        this.factory = factory;
     }
 
     public getDataItem(): DataItem {
         return this.dataItem;
     }
 
+    public getFactory(): DataTypeFactory {
+        return this.factory;
+    }
+
     public encode(value: any, rules?: EncodingRules, selector?: string): string {
         const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
         const calldata = new Calldata(rules_);
@@ -45,8 +56,8 @@ export abstract class DataType {
 export abstract class PayloadDataType extends DataType {
     protected hasConstantSize: boolean;
 
-    public constructor(dataItem: DataItem, hasConstantSize: boolean) {
-        super(dataItem);
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+        super(dataItem, factory);
         this.hasConstantSize = hasConstantSize;
     }
 
@@ -78,8 +89,8 @@ export abstract class DependentDataType extends DataType {
     protected dependency: DataType;
     protected parent: DataType;
 
-    public constructor(dataItem: DataItem, dependency: DataType, parent: DataType) {
-        super(dataItem);
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+        super(dataItem, factory);
         this.dependency = dependency;
         this.parent = parent;
     }
@@ -125,8 +136,8 @@ export abstract class MemberDataType extends DataType {
     protected arrayElementType: string | undefined;
 
 
-    public constructor(dataItem: DataItem, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
-        super(dataItem);
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
+        super(dataItem, factory);
         this.memberMap = {};
         this.members = [];
         this.isArray = isArray;
@@ -156,7 +167,7 @@ export abstract class MemberDataType extends DataType {
             if (components !== undefined) {
                 childDataItem.components = components;
             }
-            const child = DataTypeFactory.create(childDataItem, this);
+            const child = this.getFactory().create(childDataItem, this);
             memberMap[memberItem.name] = members.length;
             members.push(child);
         });
@@ -177,7 +188,7 @@ export abstract class MemberDataType extends DataType {
             if (components !== undefined) {
                 childDataItem.components = components;
             }
-            const child = DataTypeFactory.create(childDataItem, this);
+            const child = this.getFactory().create(childDataItem, this);
             memberMap[idx.toString(10)] = members.length;
             members.push(child);
         });
@@ -309,46 +320,3 @@ export abstract class MemberDataType extends DataType {
         return isStatic;
     }
 }
-
-export interface DataTypeFactoryImpl {
-    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
-    mapDataItemToDataType: (dataItem: DataItem) => DataType;
-}
-
-export class DataTypeFactory {
-    private static instance: DataTypeFactory;
-    private provider: DataTypeFactoryImpl | undefined;
-
-    private constructor() { }
-
-    private static getInstance(): DataTypeFactory {
-        if (!DataTypeFactory.instance) {
-            DataTypeFactory.instance = new DataTypeFactory();
-        }
-        return DataTypeFactory.instance;
-    }
-
-    public static setImpl(provider: DataTypeFactoryImpl) {
-        const instance = DataTypeFactory.getInstance();
-        if (instance.provider !== undefined) {
-            throw new Error(`Tried to set implementation more than once`);
-        }
-        DataTypeFactory.getInstance().provider = provider;
-    }
-
-    public static create(dataItem: DataItem, parentDataType: DataType): DataType {
-        const instance = DataTypeFactory.getInstance();
-        if (instance.provider === undefined) {
-            throw new Error(`Tried to create before implementation is set`);
-        }
-        return instance.provider.create(dataItem, parentDataType);
-    }
-
-    public static mapDataItemToDataType(dataItem: DataItem): DataType {
-        const instance = DataTypeFactory.getInstance();
-        if (instance.provider === undefined) {
-            throw new Error(`Tried to create before implementation is set`);
-        }
-        return instance.provider.mapDataItemToDataType(dataItem);
-    }
-}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index aff4bc991..bb7c1d81d 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -1,4 +1,4 @@
-import { DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+import { DataType, DataTypeFactory, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
 
 import { DecodingRules, EncodingRules } from './calldata';
 
@@ -22,7 +22,7 @@ export class Address extends PayloadDataType {
     private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
     constructor(dataItem: DataItem) {
-        super(dataItem, Address.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
         if (!Address.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
         }
@@ -54,7 +54,7 @@ export class Bool extends PayloadDataType {
     private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
     constructor(dataItem: DataItem) {
-        super(dataItem, Bool.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bool.SIZE_KNOWN_AT_COMPILE_TIME);
         if (!Bool.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
         }
@@ -94,7 +94,7 @@ abstract class Number extends PayloadDataType {
     width: number = Number.DEFAULT_WIDTH;
 
     constructor(dataItem: DataItem, matcher: RegExp) {
-        super(dataItem, Number.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), Number.SIZE_KNOWN_AT_COMPILE_TIME);
         const matches = matcher.exec(dataItem.type);
         if (matches === null) {
             throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
@@ -243,7 +243,7 @@ export class Byte extends PayloadDataType {
     width: number = Byte.DEFAULT_WIDTH;
 
     constructor(dataItem: DataItem) {
-        super(dataItem, Byte.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), Byte.SIZE_KNOWN_AT_COMPILE_TIME);
         const matches = Byte.matcher.exec(dataItem.type);
         if (!Byte.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
@@ -297,7 +297,7 @@ export class Bytes extends PayloadDataType {
     length: BigNumber = Bytes.UNDEFINED_LENGTH;
 
     constructor(dataItem: DataItem) {
-        super(dataItem, Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
         if (!Bytes.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
         }
@@ -343,7 +343,7 @@ export class Bytes extends PayloadDataType {
 export class SolString extends PayloadDataType {
     private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
     constructor(dataItem: DataItem) {
-        super(dataItem, SolString.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), SolString.SIZE_KNOWN_AT_COMPILE_TIME);
         if (!SolString.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
         }
@@ -383,7 +383,7 @@ export class Pointer extends DependentDataType {
     constructor(destDataType: DataType, parentDataType: DataType) {
         const destDataItem = destDataType.getDataItem();
         const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
-        super(dataItem, destDataType, parentDataType);
+        super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
     }
 
     public getSignature(): string {
@@ -395,7 +395,7 @@ export class Tuple extends MemberDataType {
     private tupleSignature: string;
 
     constructor(dataItem: DataItem) {
-        super(dataItem);
+        super(dataItem, EvmDataTypeFactory.getInstance());
         if (!Tuple.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
         }
@@ -430,7 +430,7 @@ export class SolArray extends MemberDataType {
         const isArray = true;
         const arrayElementType = matches[1];
         const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
-        super(dataItem, isArray, arrayLength, arrayElementType);
+        super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
         this.elementType = arrayElementType;
         this.arraySignature = this.computeSignature();
     }
@@ -444,7 +444,7 @@ export class SolArray extends MemberDataType {
         if (components !== undefined) {
             dataItem.components = components;
         }
-        const elementDataType = DataTypeFactory.mapDataItemToDataType(dataItem);
+        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
         const type = elementDataType.getSignature();
         if (this.arrayLength === undefined) {
             return `${type}[]`;
@@ -470,7 +470,7 @@ export class Method extends MemberDataType {
     public selector: string;
 
     constructor(abi: MethodAbi) {
-        super({ type: 'method', name: abi.name, components: abi.inputs });
+        super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
         this.methodSignature = this.computeSignature();
         this.selector = this.methodSelector = this.computeSelector();
 
@@ -510,7 +510,17 @@ export class Method extends MemberDataType {
     }
 }
 
-export class EvmDataTypeFactoryImpl implements DataTypeFactoryImpl {
+export class EvmDataTypeFactory implements DataTypeFactory {
+    private static instance: DataTypeFactory;
+
+    private constructor() { }
+
+    public static getInstance(): DataTypeFactory {
+        if (!EvmDataTypeFactory.instance) {
+            EvmDataTypeFactory.instance = new EvmDataTypeFactory();
+        }
+        return EvmDataTypeFactory.instance;
+    }
 
     public mapDataItemToDataType(dataItem: DataItem): DataType {
         if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 8ae23a222..295311acc 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -19,8 +19,6 @@ import * as AbiEncoder from './abi/abi_encoder';
 import * as AbiSamples from './abi_samples';
 import { Calldata } from './abi/calldata';
 
-AbiEncoder.DataTypeFactory.setImpl(new AbiEncoder.EvmDataTypeFactoryImpl());
-
 chaiSetup.configure();
 const expect = chai.expect;
 
@@ -56,7 +54,7 @@ describe.only('ABI Encoder', () => {
             console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
         });
 
-        it.only('Should point array elements to a duplicated value from another parameter', async () => {
+        it('Should point array elements to a duplicated value from another parameter', async () => {
             const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
             const stringArray = [
                 "Test String",
-- 
cgit v1.2.3


From 71c050375b23336e7bc2700b595032eefe0ca4c1 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 15:15:01 -0800
Subject: Restructured to use index.ts for easier imports by client

---
 packages/order-utils/test/abi/abi_encoder.ts       |   3 -
 packages/order-utils/test/abi/calldata.ts          | 520 -------------------
 packages/order-utils/test/abi/data_type.ts         | 322 ------------
 packages/order-utils/test/abi/evm_data_types.ts    | 550 ---------------------
 packages/order-utils/test/abi_encoder/calldata.ts  | 520 +++++++++++++++++++
 packages/order-utils/test/abi_encoder/data_type.ts | 322 ++++++++++++
 .../order-utils/test/abi_encoder/evm_data_types.ts | 550 +++++++++++++++++++++
 packages/order-utils/test/abi_encoder/index.ts     |   2 +
 packages/order-utils/test/abi_encoder_test.ts      |   5 +-
 9 files changed, 1396 insertions(+), 1398 deletions(-)
 delete mode 100644 packages/order-utils/test/abi/abi_encoder.ts
 delete mode 100644 packages/order-utils/test/abi/calldata.ts
 delete mode 100644 packages/order-utils/test/abi/data_type.ts
 delete mode 100644 packages/order-utils/test/abi/evm_data_types.ts
 create mode 100644 packages/order-utils/test/abi_encoder/calldata.ts
 create mode 100644 packages/order-utils/test/abi_encoder/data_type.ts
 create mode 100644 packages/order-utils/test/abi_encoder/evm_data_types.ts
 create mode 100644 packages/order-utils/test/abi_encoder/index.ts

diff --git a/packages/order-utils/test/abi/abi_encoder.ts b/packages/order-utils/test/abi/abi_encoder.ts
deleted file mode 100644
index 4f4906550..000000000
--- a/packages/order-utils/test/abi/abi_encoder.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './calldata';
-export * from './data_type';
-export * from './evm_data_types';
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
deleted file mode 100644
index 32278e5c5..000000000
--- a/packages/order-utils/test/abi/calldata.ts
+++ /dev/null
@@ -1,520 +0,0 @@
-import ethUtil = require('ethereumjs-util');
-import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
-var _ = require('lodash');
-
-export interface DecodingRules {
-    structsAsObjects: boolean;
-}
-
-export interface EncodingRules {
-    optimize?: boolean;
-    annotate?: boolean;
-}
-
-export abstract class CalldataBlock {
-    private name: string;
-    private signature: string;
-    private offsetInBytes: number;
-    private headerSizeInBytes: number;
-    private bodySizeInBytes: number;
-    private relocatable: boolean;
-    private parentName: string;
-
-    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
-        this.name = name;
-        this.signature = signature;
-        this.parentName = parentName;
-        this.offsetInBytes = 0;
-        this.headerSizeInBytes = headerSizeInBytes;
-        this.bodySizeInBytes = bodySizeInBytes;
-        this.relocatable = relocatable;
-    }
-
-    protected setHeaderSize(headerSizeInBytes: number) {
-        this.headerSizeInBytes = headerSizeInBytes;
-    }
-
-    protected setBodySize(bodySizeInBytes: number) {
-        this.bodySizeInBytes = bodySizeInBytes;
-    }
-
-    protected setName(name: string) {
-        this.name = name;
-    }
-
-    public getName(): string {
-        return this.name;
-    }
-
-    public getParentName(): string {
-        return this.parentName;
-    }
-
-    public getSignature(): string {
-        return this.signature;
-    }
-
-    public isRelocatable(): boolean {
-        return this.relocatable;
-    }
-
-    public getHeaderSizeInBytes(): number {
-        return this.headerSizeInBytes;
-    }
-
-    public getBodySizeInBytes(): number {
-        return this.bodySizeInBytes;
-    }
-
-    public getSizeInBytes(): number {
-        return this.headerSizeInBytes + this.bodySizeInBytes;
-    }
-
-    public getOffsetInBytes(): number {
-        return this.offsetInBytes;
-    }
-
-    public setOffset(offsetInBytes: number) {
-        this.offsetInBytes = offsetInBytes;
-    }
-
-    public computeHash(): Buffer {
-        const rawData = this.getRawData();
-        const hash = ethUtil.sha3(rawData);
-        return hash;
-    }
-
-    public abstract toBuffer(): Buffer;
-    public abstract getRawData(): Buffer;
-}
-
-export class PayloadCalldataBlock extends CalldataBlock {
-    private payload: Buffer;
-
-    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = payload.byteLength;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
-        this.payload = payload;
-    }
-
-    public toBuffer(): Buffer {
-        return this.payload;
-    }
-
-    public getRawData(): Buffer {
-        return this.payload;
-    }
-}
-
-export class DependentCalldataBlock extends CalldataBlock {
-    public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    public static RAW_DATA_START = new Buffer('<');
-    public static RAW_DATA_END = new Buffer('>');
-    private parent: CalldataBlock;
-    private dependency: CalldataBlock;
-    private aliasFor: CalldataBlock | undefined;
-
-    constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
-        this.parent = parent;
-        this.dependency = dependency;
-        this.aliasFor = undefined;
-    }
-
-    public toBuffer(): Buffer {
-        const destinationOffset = (this.aliasFor !== undefined) ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
-        const parentOffset = this.parent.getOffsetInBytes();
-        const parentHeaderSize = this.parent.getHeaderSizeInBytes();
-        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
-        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
-        const evmWordWidthInBytes = 32;
-        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
-        return pointerBufPadded;
-    }
-
-    public getDependency(): CalldataBlock {
-        return this.dependency;
-    }
-
-    public setAlias(block: CalldataBlock) {
-        this.aliasFor = block;
-        this.setName(`${this.getName()} (alias for ${block.getName()})`);
-    }
-
-    public getAlias(): CalldataBlock | undefined {
-        return this.aliasFor;
-    }
-
-    public getRawData(): Buffer {
-        const dependencyRawData = this.dependency.getRawData();
-        const rawDataComponents: Buffer[] = [];
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
-        rawDataComponents.push(dependencyRawData);
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-}
-
-export class MemberCalldataBlock extends CalldataBlock {
-    private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    private header: Buffer | undefined;
-    private members: CalldataBlock[];
-    private contiguous: boolean;
-
-    constructor(name: string, signature: string, parentName: string, relocatable: boolean, contiguous: boolean) {
-        super(name, signature, parentName, 0, 0, relocatable);
-        this.members = [];
-        this.header = undefined;
-        this.contiguous = contiguous;
-    }
-
-    public getRawData(): Buffer {
-        const rawDataComponents: Buffer[] = [];
-        if (this.header !== undefined) {
-            rawDataComponents.push(this.header);
-        }
-        _.each(this.members, (member: CalldataBlock) => {
-            const memberBuffer = member.getRawData();
-            rawDataComponents.push(memberBuffer);
-        });
-
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-
-    public setMembers(members: CalldataBlock[]) {
-        let bodySizeInBytes = 0;
-        _.each(members, (member: CalldataBlock) => {
-            bodySizeInBytes += member.getSizeInBytes();
-        });
-        this.members = members;
-        this.setBodySize(0);
-    }
-
-    public isContiguous(): boolean {
-        return true;
-    }
-
-    public setHeader(header: Buffer) {
-        this.setHeaderSize(header.byteLength);
-        this.header = header;
-    }
-
-    public toBuffer(): Buffer {
-        if (this.header !== undefined) return this.header;
-        return new Buffer('');
-    }
-
-    public getMembers(): CalldataBlock[] {
-        return this.members;
-    }
-}
-
-class Queue<T> {
-    private store: T[] = [];
-    push(val: T) {
-        this.store.push(val);
-    }
-    pushFront(val: T) {
-        this.store.unshift(val);
-    }
-    pop(): T | undefined {
-        return this.store.shift();
-    }
-    popBack(): T | undefined {
-        if (this.store.length === 0) return undefined;
-        const backElement = this.store.splice(-1, 1)[0];
-        return backElement;
-    }
-    merge(q: Queue<T>) {
-        this.store = this.store.concat(q.store);
-    }
-    mergeFront(q: Queue<T>) {
-        this.store = q.store.concat(this.store);
-    }
-    getStore(): T[] {
-        return this.store;
-    }
-    peek(): T | undefined {
-        return this.store.length >= 0 ? this.store[0] : undefined;
-    }
-}
-
-export class Calldata {
-    private selector: string;
-    private rules: EncodingRules;
-    private sizeInBytes: number;
-    private root: MemberCalldataBlock | undefined;
-
-    constructor(rules: EncodingRules) {
-        this.selector = '';
-        this.rules = rules;
-        this.sizeInBytes = 0;
-        this.root = undefined;
-    }
-
-    private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> {
-        const blockQueue = new Queue<CalldataBlock>();
-        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof MemberCalldataBlock) {
-                blockQueue.mergeFront(this.createQueue(member));
-            } else {
-                blockQueue.pushFront(member);
-            }
-        });
-
-        // Children
-        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
-                let dependency = member.getDependency();
-                if (dependency instanceof MemberCalldataBlock) {
-                    blockQueue.merge(this.createQueue(dependency));
-                } else {
-                    blockQueue.push(dependency);
-                }
-            }
-        });
-
-        blockQueue.pushFront(memberBlock);
-        return blockQueue;
-    }
-
-    private generateAnnotatedHexString(): string {
-        let hexValue = `${this.selector}`;
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = this.createQueue(this.root);
-
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        const functionBlock = valueQueue.peek();
-        let functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
-        while ((block = valueQueue.pop()) !== undefined) {
-            // Set f
-
-            // Process each block 1 word at a time
-            const size = block.getSizeInBytes();
-            const name = block.getName();
-            const parentName = block.getParentName();
-
-            //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
-            //const parentOffset = name.lastIndexOf(parentName);
-            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');//.replace(`${parentName}[`, '[');
-            const signature = block.getSignature();
-
-            // Current offset
-            let offsetStr = '';
-
-            // If this block is empty then it's a newline
-            let value = '';
-            let nameStr = '';
-            let line = '';
-            if (size === 0) {
-                offsetStr = ' '.repeat(10);
-                value = ' '.repeat(74);
-                nameStr = `### ${prettyName.padEnd(80)}`;
-                line = `\n${offsetStr}${value}${nameStr}`;
-            } else {
-                offsetStr = `0x${offset.toString(16)}`.padEnd(10, ' ');
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(0, 32))).padEnd(74);
-                if (block instanceof MemberCalldataBlock) {
-                    nameStr = `### ${prettyName.padEnd(80)}`;
-                    line = `\n${offsetStr}${value}${nameStr}`;
-                } else {
-                    nameStr = `    ${prettyName.padEnd(80)}`;
-                    line = `${offsetStr}${value}${nameStr}`;
-                }
-            }
-
-            for (let j = 32; j < size; j += 32) {
-                offsetStr = `0x${(offset + j).toString(16)}`.padEnd(10, ' ');
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + 32))).padEnd(74);
-                nameStr = ' '.repeat(40);
-
-                line = `${line}\n${offsetStr}${value}${nameStr}`;
-            }
-
-            // Append to hex value
-            hexValue = `${hexValue}\n${line}`;
-            offset += size;
-        }
-
-        return hexValue;
-    }
-
-    private generateCondensedHexString(): string {
-        let selectorBuffer = ethUtil.toBuffer(this.selector);
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = this.createQueue(this.root);
-        const valueBufs: Buffer[] = [selectorBuffer];
-        let block: CalldataBlock | undefined;
-        while ((block = valueQueue.pop()) !== undefined) {
-            valueBufs.push(block.toBuffer());
-        }
-
-        const combinedBuffers = Buffer.concat(valueBufs);
-        const hexValue = ethUtil.bufferToHex(combinedBuffers);
-        return hexValue;
-    }
-
-    public optimize() {
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const blocksByHash: { [key: string]: CalldataBlock } = {};
-
-        // 1. Create a queue of subtrees by hash
-        // Note that they are ordered the same as 
-        const subtreeQueue = this.createQueue(this.root);
-        let block: CalldataBlock | undefined;
-        while ((block = subtreeQueue.popBack()) !== undefined) {
-            if (block instanceof DependentCalldataBlock) {
-                const blockHashBuf = block.getDependency().computeHash();
-                const blockHash = ethUtil.bufferToHex(blockHashBuf);
-                if (blockHash in blocksByHash) {
-                    const blockWithSameHash = blocksByHash[blockHash];
-                    if (blockWithSameHash !== block.getDependency()) {
-                        block.setAlias(blockWithSameHash);
-                    }
-                }
-                continue;
-            }
-
-            const blockHashBuf = block.computeHash();
-            const blockHash = ethUtil.bufferToHex(blockHashBuf);
-            if (blockHash in blocksByHash === false) {
-                blocksByHash[blockHash] = block;
-            }
-        }
-    }
-
-    public toHexString(): string {
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        if (this.rules.optimize) this.optimize();
-
-        const offsetQueue = this.createQueue(this.root);
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        while ((block = offsetQueue.pop()) !== undefined) {
-            block.setOffset(offset);
-            offset += block.getSizeInBytes();
-        }
-
-        const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
-        return hexValue;
-    }
-
-    public getSelectorHex(): string {
-        return this.selector;
-    }
-
-    public getSizeInBytes(): number {
-        return this.sizeInBytes;
-    }
-
-    public toAnnotatedString(): string {
-        return "";
-    }
-
-    public setRoot(block: MemberCalldataBlock) {
-        this.root = block;
-        this.sizeInBytes += block.getSizeInBytes();
-    }
-
-    public setSelector(selector: string) {
-        // Ensure we have a 0x prefix
-        if (selector.startsWith('0x')) {
-            this.selector = selector;
-        } else {
-            this.selector = `$0x${selector}`;
-        }
-
-        // The selector must be 10 characters: '0x' followed by 4 bytes (two hex chars per byte)
-        if (this.selector.length !== 10) {
-            throw new Error(`Invalid selector '${this.selector}'`);
-        }
-        this.sizeInBytes += 8;
-    }
-}
-
-export class RawCalldata {
-    private value: Buffer;
-    private offset: number; // tracks current offset into raw calldata; used for parsing
-    private selector: string;
-    private scopes: Queue<number>;
-
-    constructor(value: string | Buffer) {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Expected raw calldata to start with '0x'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
-        this.value = valueBuf.slice(4); // disregard selector
-        this.offset = 0;
-        this.scopes = new Queue<number>();
-        this.scopes.push(0);
-    }
-
-    public popBytes(lengthInBytes: number): Buffer {
-        const value = this.value.slice(this.offset, this.offset + lengthInBytes);
-        this.setOffset(this.offset + lengthInBytes);
-        return value;
-    }
-
-    public popWord(): Buffer {
-        const wordInBytes = 32;
-        return this.popBytes(wordInBytes);
-    }
-
-    public popWords(length: number): Buffer {
-        const wordInBytes = 32;
-        return this.popBytes(length * wordInBytes);
-    }
-
-    public readBytes(from: number, to: number): Buffer {
-        const value = this.value.slice(from, to);
-        return value;
-    }
-
-    public setOffset(offsetInBytes: number) {
-        this.offset = offsetInBytes;
-    }
-
-    public startScope() {
-        this.scopes.pushFront(this.offset);
-    }
-
-    public endScope() {
-        this.scopes.pop();
-    }
-
-    public getOffset(): number {
-        return this.offset;
-    }
-
-    public toAbsoluteOffset(relativeOffset: number) {
-        const scopeOffset = this.scopes.peek();
-        if (scopeOffset === undefined) {
-            throw new Error(`Tried to access undefined scope.`);
-        }
-        const absoluteOffset = relativeOffset + scopeOffset;
-        return absoluteOffset;
-    }
-
-    public getSelector(): string {
-        return this.selector;
-    }
-}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
deleted file mode 100644
index 4c4537a69..000000000
--- a/packages/order-utils/test/abi/data_type.ts
+++ /dev/null
@@ -1,322 +0,0 @@
-import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
-import { MethodAbi, DataItem } from 'ethereum-types';
-import { DecodingRules, EncodingRules } from './calldata';
-import { BigNumber } from '@0x/utils';
-import ethUtil = require('ethereumjs-util');
-var _ = require('lodash');
-
-export interface DataTypeFactory {
-    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
-    mapDataItemToDataType: (dataItem: DataItem) => DataType;
-}
-
-export abstract class DataType {
-    private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
-    private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
-
-    private dataItem: DataItem;
-    private factory: DataTypeFactory;
-
-    constructor(dataItem: DataItem, factory: DataTypeFactory) {
-        this.dataItem = dataItem;
-        this.factory = factory;
-    }
-
-    public getDataItem(): DataItem {
-        return this.dataItem;
-    }
-
-    public getFactory(): DataTypeFactory {
-        return this.factory;
-    }
-
-    public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
-        const calldata = new Calldata(rules_);
-        if (selector) calldata.setSelector(selector);
-        const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
-        const calldataHex = calldata.toHexString();
-        return calldataHex;
-    }
-
-    public decode(calldata: string, rules?: DecodingRules): any {
-        const rawCalldata = new RawCalldata(calldata);
-        const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
-        const value = this.generateValue(rawCalldata, rules_);
-        return value;
-    }
-
-    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
-    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
-    public abstract getSignature(): string;
-    public abstract isStatic(): boolean;
-}
-
-export abstract class PayloadDataType extends DataType {
-    protected hasConstantSize: boolean;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
-        super(dataItem, factory);
-        this.hasConstantSize = hasConstantSize;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
-        const encodedValue = this.encodeValue(value);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const relocatable = false;
-        const block = new PayloadCalldataBlock(name, signature, parentName, /*offsetInBytes,*/ relocatable, encodedValue);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const value = this.decodeValue(calldata);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        // If a payload has a constant size then it's static
-        return this.hasConstantSize;
-    }
-
-    public abstract encodeValue(value: any): Buffer;
-    public abstract decodeValue(calldata: RawCalldata): any;
-}
-
-export abstract class DependentDataType extends DataType {
-    protected dependency: DataType;
-    protected parent: DataType;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
-        super(dataItem, factory);
-        this.dependency = dependency;
-        this.parent = parent;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
-        if (parentBlock === undefined) {
-            throw new Error(`DependentDataType requires a parent block to generate its block`);
-        }
-        const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const relocatable = false;
-        const block = new DependentCalldataBlock(name, signature, parentName, relocatable, dependencyBlock, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const destinationOffsetBuf = calldata.popWord();
-        const currentOffset = calldata.getOffset();
-        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
-        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
-        calldata.setOffset(destinationOffsetAbsolute);
-        const value = this.dependency.generateValue(calldata, rules);
-        calldata.setOffset(currentOffset);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-}
-
-export interface MemberMap {
-    [key: string]: number;
-}
-
-export abstract class MemberDataType extends DataType {
-    private memberMap: MemberMap;
-    private members: DataType[];
-    private isArray: boolean;
-    protected arrayLength: number | undefined;
-    protected arrayElementType: string | undefined;
-
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
-        super(dataItem, factory);
-        this.memberMap = {};
-        this.members = [];
-        this.isArray = isArray;
-        this.arrayLength = arrayLength;
-        this.arrayElementType = arrayElementType;
-        if (isArray && arrayLength !== undefined) {
-            [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
-        } else if (!isArray) {
-            [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
-        }
-    }
-
-    private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
-        // Sanity check
-        if (dataItem.components === undefined) {
-            throw new Error(`Expected components`);
-        }
-
-        let members: DataType[] = [];
-        let memberMap: MemberMap = {};
-        _.each(dataItem.components, (memberItem: DataItem) => {
-            const childDataItem = {
-                type: memberItem.type,
-                name: `${dataItem.name}.${memberItem.name}`,
-            } as DataItem;
-            const components = memberItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[memberItem.name] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberMap];
-    }
-
-    private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
-        let members: DataType[] = [];
-        let memberMap: MemberMap = {};
-        const range = _.range(length);
-        _.each(range, (idx: number) => {
-            const childDataItem = {
-                type: this.arrayElementType,
-                name: `${dataItem.name}[${idx.toString(10)}]`,
-            } as DataItem;
-            const components = dataItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[idx.toString(10)] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberMap];
-    }
-
-    protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
-        // Sanity check length
-        if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
-            throw new Error(
-                `Expected array of ${JSON.stringify(
-                    this.arrayLength,
-                )} elements, but got array of length ${JSON.stringify(value.length)}`,
-            );
-        }
-
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
-
-        let members = this.members;
-        if (this.isArray && this.arrayLength === undefined) {
-            [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
-
-            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
-            methodBlock.setHeader(lenBuf);
-        }
-
-        const memberBlocks: CalldataBlock[] = [];
-        _.each(members, (member: DataType, idx: number) => {
-            const block = member.generateCalldataBlock(value[idx], methodBlock);
-            memberBlocks.push(block);
-        });
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
-        const memberBlocks: CalldataBlock[] = [];
-        let childMap = _.cloneDeep(this.memberMap);
-        _.forOwn(obj, (value: any, key: string) => {
-            if (key in childMap === false) {
-                throw new Error(`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`);
-            }
-            const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
-            memberBlocks.push(block);
-            delete childMap[key];
-        });
-
-        if (Object.keys(childMap).length !== 0) {
-            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
-        }
-
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value, parentBlock) : this.generateCalldataBlockFromObject(value, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
-        let members = this.members;
-        if (this.isArray && this.arrayLength === undefined) {
-            const arrayLengthBuf = calldata.popWord();
-            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const hexBase = 16;
-            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
-            [members,] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
-        }
-
-        calldata.startScope();
-        let value: any[] | object;
-        if (rules.structsAsObjects && !this.isArray) {
-            value = {};
-            _.each(this.memberMap, (idx: number, key: string) => {
-                const member = this.members[idx];
-                let memberValue = member.generateValue(calldata, rules);
-                (value as { [key: string]: any })[key] = memberValue;
-            });
-        } else {
-            value = [];
-            _.each(members, (member: DataType, idx: number) => {
-                let memberValue = member.generateValue(calldata, rules);
-                (value as any[]).push(memberValue);
-            });
-        }
-        calldata.endScope();
-        return value;
-    }
-
-    protected computeSignatureOfMembers(): string {
-        // Compute signature of members
-        let signature = `(`;
-        _.each(this.members, (member: DataType, i: number) => {
-            signature += member.getSignature();
-            if (i < this.members.length - 1) {
-                signature += ',';
-            }
-        });
-        signature += ')';
-        return signature;
-    }
-
-    public isStatic(): boolean {
-        /* For Tuple:
-                    const isStaticTuple = this.children.length === 0;
-                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
-           For Array:
-                if isLengthDefined = false then this is false
-
-                Otherwise if the first element is a Pointer then false
-        */
-
-        if (this.isArray && this.arrayLength === undefined) {
-            return false;
-        }
-
-        // Search for dependent members
-        const dependentMember = _.find(this.members, (member: DataType) => {
-            return (member instanceof DependentDataType);
-        });
-        const isStatic = (dependentMember === undefined); // static if we couldn't find a dependent member
-        return isStatic;
-    }
-}
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
deleted file mode 100644
index bb7c1d81d..000000000
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ /dev/null
@@ -1,550 +0,0 @@
-import { DataType, DataTypeFactory, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
-
-import { DecodingRules, EncodingRules } from './calldata';
-
-import { MethodAbi, DataItem } from 'ethereum-types';
-
-import ethUtil = require('ethereumjs-util');
-
-import { Calldata, RawCalldata } from './calldata';
-
-import { BigNumber } from '@0x/utils';
-
-var _ = require('lodash');
-
-export interface DataTypeStaticInterface {
-    matchGrammar: (type: string) => boolean;
-    encodeValue: (value: any) => Buffer;
-    decodeValue: (rawCalldata: RawCalldata) => any;
-}
-
-export class Address extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Address.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
-        }
-    }
-
-    public getSignature(): string {
-        return 'address';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'address';
-    }
-
-    public encodeValue(value: boolean): Buffer {
-        const evmWordWidth = 32;
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(12);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
-    }
-}
-
-export class Bool extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bool.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bool.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
-        }
-    }
-
-    public getSignature(): string {
-        return 'bool';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'bool';
-    }
-
-    public encodeValue(value: boolean): Buffer {
-        const evmWordWidth = 32;
-        const encodedValue = value === true ? '0x1' : '0x0';
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): boolean {
-        const valueBuf = calldata.popWord();
-        const valueHex = ethUtil.bufferToHex(valueBuf);
-        const valueNumber = new BigNumber(valueHex, 16);
-        let value: boolean = (valueNumber.equals(0)) ? false : true;
-        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
-            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
-        }
-        return value;
-    }
-}
-
-abstract class Number extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    static MAX_WIDTH: number = 256;
-    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
-    width: number = Number.DEFAULT_WIDTH;
-
-    constructor(dataItem: DataItem, matcher: RegExp) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Number.SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = matcher.exec(dataItem.type);
-        if (matches === null) {
-            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
-        }
-        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
-            this.width = parseInt(matches[1]);
-        } else {
-            this.width = 256;
-        }
-    }
-
-    public encodeValue(value: BigNumber): Buffer {
-        if (value.greaterThan(this.getMaxValue())) {
-            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
-        } else if (value.lessThan(this.getMinValue())) {
-            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
-        }
-
-        const hexBase = 16;
-        const evmWordWidth = 32;
-        let valueBuf: Buffer;
-        if (value.greaterThanOrEqualTo(0)) {
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
-        } else {
-            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
-            // Step 1/3: Convert value to positive binary string
-            const binBase = 2;
-            const valueBin = value.times(-1).toString(binBase);
-
-            // Step 2/3: Invert binary value
-            const bitsInEvmWord = 256;
-            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
-            _.each(valueBin, (bit: string) => {
-                invertedValueBin += bit === '1' ? '0' : '1';
-            });
-            const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-            // Step 3/3: Add 1 to inverted value
-            // The result is the two's-complement represent of the input value.
-            const negativeValue = invertedValue.plus(1);
-
-            // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
-                evmWordWidth,
-            );
-        }
-
-        return valueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): BigNumber {
-        const paddedValueBuf = calldata.popWord();
-        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
-        let value = new BigNumber(paddedValueHex, 16);
-        if (this instanceof Int) {
-            // Check if we're negative
-            const binBase = 2;
-            const paddedValueBin = value.toString(binBase);
-            const valueBin = paddedValueBin.slice(paddedValueBin.length - this.width);
-            if (valueBin[0].startsWith('1')) {
-                // Negative
-                // Step 1/3: Invert binary value
-                let invertedValueBin = '';
-                _.each(valueBin, (bit: string) => {
-                    invertedValueBin += bit === '1' ? '0' : '1';
-                });
-                const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-                // Step 2/3: Add 1 to inverted value
-                // The result is the two's-complement represent of the input value.
-                const positiveValue = invertedValue.plus(1);
-
-                // Step 3/3: Invert positive value
-                const negativeValue = positiveValue.times(-1);
-                value = negativeValue;
-            }
-        }
-
-        return value;
-    }
-
-    public abstract getMaxValue(): BigNumber;
-    public abstract getMinValue(): BigNumber;
-}
-
-export class Int extends Number {
-    static matcher = RegExp(
-        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, Int.matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).times(-1);
-    }
-
-    public getSignature(): string {
-        return `int${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class UInt extends Number {
-    static matcher = RegExp(
-        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, UInt.matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getSignature(): string {
-        return `uint${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Byte extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    static matcher = RegExp(
-        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
-    );
-
-    static DEFAULT_WIDTH = 1;
-    width: number = Byte.DEFAULT_WIDTH;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Byte.SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = Byte.matcher.exec(dataItem.type);
-        if (!Byte.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
-        }
-        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
-            this.width = parseInt(matches[2]);
-        } else {
-            this.width = Byte.DEFAULT_WIDTH;
-        }
-    }
-
-    public getSignature(): string {
-        // Note that `byte` reduces to `bytes1`
-        return `bytes${this.width}`;
-    }
-
-    public encodeValue(value: string | Buffer): Buffer {
-        // Convert value into a buffer and do bounds checking
-        const valueBuf = ethUtil.toBuffer(value);
-        if (valueBuf.byteLength > this.width) {
-            throw new Error(
-                `Tried to assign ${value} (${
-                valueBuf.byteLength
-                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
-            );
-        } else if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        // Store value as hex
-        const evmWordWidth = 32;
-        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
-        return paddedValue;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(0, this.width);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Bytes extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-    static UNDEFINED_LENGTH = new BigNumber(-1);
-    length: BigNumber = Bytes.UNDEFINED_LENGTH;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bytes.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
-        }
-    }
-
-    public encodeValue(value: string | Buffer): Buffer {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
-        const paddedBytesForValue = wordsForValue * 32;
-        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
-        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
-        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, 16);
-        const wordsForValue = Math.ceil(length / 32);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const decodedValue = ethUtil.bufferToHex(valueBuf);
-        return decodedValue;
-    }
-
-    public getSignature(): string {
-        return 'bytes';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'bytes';
-    }
-}
-
-export class SolString extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), SolString.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!SolString.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
-        }
-    }
-
-    public encodeValue(value: string): Buffer {
-        const wordsForValue = Math.ceil(value.length / 32);
-        const paddedBytesForValue = wordsForValue * 32;
-        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
-        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, 16);
-        const wordsForValue = Math.ceil(length / 32);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const value = valueBuf.toString('ascii');
-        return value;
-    }
-
-    public getSignature(): string {
-        return 'string';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'string';
-    }
-}
-
-export class Pointer extends DependentDataType {
-
-    constructor(destDataType: DataType, parentDataType: DataType) {
-        const destDataItem = destDataType.getDataItem();
-        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
-        super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
-    }
-
-    public getSignature(): string {
-        return this.dependency.getSignature();
-    }
-}
-
-export class Tuple extends MemberDataType {
-    private tupleSignature: string;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance());
-        if (!Tuple.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
-        }
-        this.tupleSignature = this.computeSignatureOfMembers();
-    }
-
-    public getSignature(): string {
-        return this.tupleSignature;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'tuple';
-    }
-}
-
-export class SolArray extends MemberDataType {
-    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
-    private arraySignature: string;
-    private elementType: string;
-
-    constructor(dataItem: DataItem) {
-        // Sanity check
-        const matches = SolArray.matcher.exec(dataItem.type);
-        if (matches === null || matches.length !== 3) {
-            throw new Error(`Could not parse array: ${dataItem.type}`);
-        } else if (matches[1] === undefined) {
-            throw new Error(`Could not parse array type: ${dataItem.type}`);
-        } else if (matches[2] === undefined) {
-            throw new Error(`Could not parse array length: ${dataItem.type}`);
-        }
-
-        const isArray = true;
-        const arrayElementType = matches[1];
-        const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
-        super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
-        this.elementType = arrayElementType;
-        this.arraySignature = this.computeSignature();
-    }
-
-    private computeSignature(): string {
-        let dataItem = {
-            type: this.elementType,
-            name: 'N/A',
-        } as DataItem;
-        const components = this.getDataItem().components;
-        if (components !== undefined) {
-            dataItem.components = components;
-        }
-        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
-        const type = elementDataType.getSignature();
-        if (this.arrayLength === undefined) {
-            return `${type}[]`;
-        } else {
-            return `${type}[${this.arrayLength}]`;
-        }
-    }
-
-    public getSignature(): string {
-        return this.arraySignature;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Method extends MemberDataType {
-    private methodSignature: string;
-    private methodSelector: string;
-
-    // TMP
-    public selector: string;
-
-    constructor(abi: MethodAbi) {
-        super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
-        this.methodSignature = this.computeSignature();
-        this.selector = this.methodSelector = this.computeSelector();
-
-    }
-
-    private computeSignature(): string {
-        const memberSignature = this.computeSignatureOfMembers();
-        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
-        return methodSignature;
-    }
-
-    private computeSelector(): string {
-        const signature = this.computeSignature();
-        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(0, 4)));
-        return selector;
-    }
-
-    public encode(value: any, rules?: EncodingRules): string {
-        const calldata = super.encode(value, rules, this.selector);
-        return calldata;
-    }
-
-    public decode(calldata: string, rules?: DecodingRules): any[] | object {
-        if (!calldata.startsWith(this.selector)) {
-            throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
-        }
-        const value = super.decode(calldata, rules);
-        return value;
-    }
-
-    public getSignature(): string {
-        return this.methodSignature;
-    }
-
-    public getSelector(): string {
-        return this.methodSelector;
-    }
-}
-
-export class EvmDataTypeFactory implements DataTypeFactory {
-    private static instance: DataTypeFactory;
-
-    private constructor() { }
-
-    public static getInstance(): DataTypeFactory {
-        if (!EvmDataTypeFactory.instance) {
-            EvmDataTypeFactory.instance = new EvmDataTypeFactory();
-        }
-        return EvmDataTypeFactory.instance;
-    }
-
-    public mapDataItemToDataType(dataItem: DataItem): DataType {
-        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
-        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
-        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
-        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
-        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
-        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
-        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
-        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
-        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
-
-        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-    }
-
-    public create(dataItem: DataItem, parentDataType: DataType): DataType {
-        const dataType = this.mapDataItemToDataType(dataItem);
-        if (dataType.isStatic()) {
-            return dataType;
-        }
-
-        const pointer = new Pointer(dataType, parentDataType);
-        return pointer;
-    }
-}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder/calldata.ts b/packages/order-utils/test/abi_encoder/calldata.ts
new file mode 100644
index 000000000..32278e5c5
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder/calldata.ts
@@ -0,0 +1,520 @@
+import ethUtil = require('ethereumjs-util');
+import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
+var _ = require('lodash');
+
+export interface DecodingRules {
+    structsAsObjects: boolean;
+}
+
+export interface EncodingRules {
+    optimize?: boolean;
+    annotate?: boolean;
+}
+
+export abstract class CalldataBlock {
+    private name: string;
+    private signature: string;
+    private offsetInBytes: number;
+    private headerSizeInBytes: number;
+    private bodySizeInBytes: number;
+    private relocatable: boolean;
+    private parentName: string;
+
+    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
+        this.name = name;
+        this.signature = signature;
+        this.parentName = parentName;
+        this.offsetInBytes = 0;
+        this.headerSizeInBytes = headerSizeInBytes;
+        this.bodySizeInBytes = bodySizeInBytes;
+        this.relocatable = relocatable;
+    }
+
+    protected setHeaderSize(headerSizeInBytes: number) {
+        this.headerSizeInBytes = headerSizeInBytes;
+    }
+
+    protected setBodySize(bodySizeInBytes: number) {
+        this.bodySizeInBytes = bodySizeInBytes;
+    }
+
+    protected setName(name: string) {
+        this.name = name;
+    }
+
+    public getName(): string {
+        return this.name;
+    }
+
+    public getParentName(): string {
+        return this.parentName;
+    }
+
+    public getSignature(): string {
+        return this.signature;
+    }
+
+    public isRelocatable(): boolean {
+        return this.relocatable;
+    }
+
+    public getHeaderSizeInBytes(): number {
+        return this.headerSizeInBytes;
+    }
+
+    public getBodySizeInBytes(): number {
+        return this.bodySizeInBytes;
+    }
+
+    public getSizeInBytes(): number {
+        return this.headerSizeInBytes + this.bodySizeInBytes;
+    }
+
+    public getOffsetInBytes(): number {
+        return this.offsetInBytes;
+    }
+
+    public setOffset(offsetInBytes: number) {
+        this.offsetInBytes = offsetInBytes;
+    }
+
+    public computeHash(): Buffer {
+        const rawData = this.getRawData();
+        const hash = ethUtil.sha3(rawData);
+        return hash;
+    }
+
+    public abstract toBuffer(): Buffer;
+    public abstract getRawData(): Buffer;
+}
+
+export class PayloadCalldataBlock extends CalldataBlock {
+    private payload: Buffer;
+
+    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = payload.byteLength;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.payload = payload;
+    }
+
+    public toBuffer(): Buffer {
+        return this.payload;
+    }
+
+    public getRawData(): Buffer {
+        return this.payload;
+    }
+}
+
+export class DependentCalldataBlock extends CalldataBlock {
+    public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    public static RAW_DATA_START = new Buffer('<');
+    public static RAW_DATA_END = new Buffer('>');
+    private parent: CalldataBlock;
+    private dependency: CalldataBlock;
+    private aliasFor: CalldataBlock | undefined;
+
+    constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.parent = parent;
+        this.dependency = dependency;
+        this.aliasFor = undefined;
+    }
+
+    public toBuffer(): Buffer {
+        const destinationOffset = (this.aliasFor !== undefined) ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
+        const parentOffset = this.parent.getOffsetInBytes();
+        const parentHeaderSize = this.parent.getHeaderSizeInBytes();
+        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
+        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
+        const evmWordWidthInBytes = 32;
+        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
+        return pointerBufPadded;
+    }
+
+    public getDependency(): CalldataBlock {
+        return this.dependency;
+    }
+
+    public setAlias(block: CalldataBlock) {
+        this.aliasFor = block;
+        this.setName(`${this.getName()} (alias for ${block.getName()})`);
+    }
+
+    public getAlias(): CalldataBlock | undefined {
+        return this.aliasFor;
+    }
+
+    public getRawData(): Buffer {
+        const dependencyRawData = this.dependency.getRawData();
+        const rawDataComponents: Buffer[] = [];
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
+        rawDataComponents.push(dependencyRawData);
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+}
+
+export class MemberCalldataBlock extends CalldataBlock {
+    private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private header: Buffer | undefined;
+    private members: CalldataBlock[];
+    private contiguous: boolean;
+
+    constructor(name: string, signature: string, parentName: string, relocatable: boolean, contiguous: boolean) {
+        super(name, signature, parentName, 0, 0, relocatable);
+        this.members = [];
+        this.header = undefined;
+        this.contiguous = contiguous;
+    }
+
+    public getRawData(): Buffer {
+        const rawDataComponents: Buffer[] = [];
+        if (this.header !== undefined) {
+            rawDataComponents.push(this.header);
+        }
+        _.each(this.members, (member: CalldataBlock) => {
+            const memberBuffer = member.getRawData();
+            rawDataComponents.push(memberBuffer);
+        });
+
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+
+    public setMembers(members: CalldataBlock[]) {
+        let bodySizeInBytes = 0;
+        _.each(members, (member: CalldataBlock) => {
+            bodySizeInBytes += member.getSizeInBytes();
+        });
+        this.members = members;
+        this.setBodySize(0);
+    }
+
+    public isContiguous(): boolean {
+        return true;
+    }
+
+    public setHeader(header: Buffer) {
+        this.setHeaderSize(header.byteLength);
+        this.header = header;
+    }
+
+    public toBuffer(): Buffer {
+        if (this.header !== undefined) return this.header;
+        return new Buffer('');
+    }
+
+    public getMembers(): CalldataBlock[] {
+        return this.members;
+    }
+}
+
+class Queue<T> {
+    private store: T[] = [];
+    push(val: T) {
+        this.store.push(val);
+    }
+    pushFront(val: T) {
+        this.store.unshift(val);
+    }
+    pop(): T | undefined {
+        return this.store.shift();
+    }
+    popBack(): T | undefined {
+        if (this.store.length === 0) return undefined;
+        const backElement = this.store.splice(-1, 1)[0];
+        return backElement;
+    }
+    merge(q: Queue<T>) {
+        this.store = this.store.concat(q.store);
+    }
+    mergeFront(q: Queue<T>) {
+        this.store = q.store.concat(this.store);
+    }
+    getStore(): T[] {
+        return this.store;
+    }
+    peek(): T | undefined {
+        return this.store.length >= 0 ? this.store[0] : undefined;
+    }
+}
+
+export class Calldata {
+    private selector: string;
+    private rules: EncodingRules;
+    private sizeInBytes: number;
+    private root: MemberCalldataBlock | undefined;
+
+    constructor(rules: EncodingRules) {
+        this.selector = '';
+        this.rules = rules;
+        this.sizeInBytes = 0;
+        this.root = undefined;
+    }
+
+    private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> {
+        const blockQueue = new Queue<CalldataBlock>();
+        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof MemberCalldataBlock) {
+                blockQueue.mergeFront(this.createQueue(member));
+            } else {
+                blockQueue.pushFront(member);
+            }
+        });
+
+        // Children
+        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
+                let dependency = member.getDependency();
+                if (dependency instanceof MemberCalldataBlock) {
+                    blockQueue.merge(this.createQueue(dependency));
+                } else {
+                    blockQueue.push(dependency);
+                }
+            }
+        });
+
+        blockQueue.pushFront(memberBlock);
+        return blockQueue;
+    }
+
+    private generateAnnotatedHexString(): string {
+        let hexValue = `${this.selector}`;
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = this.createQueue(this.root);
+
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        const functionBlock = valueQueue.peek();
+        let functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
+        while ((block = valueQueue.pop()) !== undefined) {
+            // Set f
+
+            // Process each block 1 word at a time
+            const size = block.getSizeInBytes();
+            const name = block.getName();
+            const parentName = block.getParentName();
+
+            //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
+            //const parentOffset = name.lastIndexOf(parentName);
+            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');//.replace(`${parentName}[`, '[');
+            const signature = block.getSignature();
+
+            // Current offset
+            let offsetStr = '';
+
+            // If this block is empty then it's a newline
+            let value = '';
+            let nameStr = '';
+            let line = '';
+            if (size === 0) {
+                offsetStr = ' '.repeat(10);
+                value = ' '.repeat(74);
+                nameStr = `### ${prettyName.padEnd(80)}`;
+                line = `\n${offsetStr}${value}${nameStr}`;
+            } else {
+                offsetStr = `0x${offset.toString(16)}`.padEnd(10, ' ');
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(0, 32))).padEnd(74);
+                if (block instanceof MemberCalldataBlock) {
+                    nameStr = `### ${prettyName.padEnd(80)}`;
+                    line = `\n${offsetStr}${value}${nameStr}`;
+                } else {
+                    nameStr = `    ${prettyName.padEnd(80)}`;
+                    line = `${offsetStr}${value}${nameStr}`;
+                }
+            }
+
+            for (let j = 32; j < size; j += 32) {
+                offsetStr = `0x${(offset + j).toString(16)}`.padEnd(10, ' ');
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + 32))).padEnd(74);
+                nameStr = ' '.repeat(40);
+
+                line = `${line}\n${offsetStr}${value}${nameStr}`;
+            }
+
+            // Append to hex value
+            hexValue = `${hexValue}\n${line}`;
+            offset += size;
+        }
+
+        return hexValue;
+    }
+
+    private generateCondensedHexString(): string {
+        let selectorBuffer = ethUtil.toBuffer(this.selector);
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = this.createQueue(this.root);
+        const valueBufs: Buffer[] = [selectorBuffer];
+        let block: CalldataBlock | undefined;
+        while ((block = valueQueue.pop()) !== undefined) {
+            valueBufs.push(block.toBuffer());
+        }
+
+        const combinedBuffers = Buffer.concat(valueBufs);
+        const hexValue = ethUtil.bufferToHex(combinedBuffers);
+        return hexValue;
+    }
+
+    public optimize() {
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const blocksByHash: { [key: string]: CalldataBlock } = {};
+
+        // 1. Create a queue of subtrees by hash
+        // Note that they are ordered the same as 
+        const subtreeQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        while ((block = subtreeQueue.popBack()) !== undefined) {
+            if (block instanceof DependentCalldataBlock) {
+                const blockHashBuf = block.getDependency().computeHash();
+                const blockHash = ethUtil.bufferToHex(blockHashBuf);
+                if (blockHash in blocksByHash) {
+                    const blockWithSameHash = blocksByHash[blockHash];
+                    if (blockWithSameHash !== block.getDependency()) {
+                        block.setAlias(blockWithSameHash);
+                    }
+                }
+                continue;
+            }
+
+            const blockHashBuf = block.computeHash();
+            const blockHash = ethUtil.bufferToHex(blockHashBuf);
+            if (blockHash in blocksByHash === false) {
+                blocksByHash[blockHash] = block;
+            }
+        }
+    }
+
+    public toHexString(): string {
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        if (this.rules.optimize) this.optimize();
+
+        const offsetQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        while ((block = offsetQueue.pop()) !== undefined) {
+            block.setOffset(offset);
+            offset += block.getSizeInBytes();
+        }
+
+        const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
+        return hexValue;
+    }
+
+    public getSelectorHex(): string {
+        return this.selector;
+    }
+
+    public getSizeInBytes(): number {
+        return this.sizeInBytes;
+    }
+
+    public toAnnotatedString(): string {
+        return "";
+    }
+
+    public setRoot(block: MemberCalldataBlock) {
+        this.root = block;
+        this.sizeInBytes += block.getSizeInBytes();
+    }
+
+    public setSelector(selector: string) {
+        // Ensure we have a 0x prefix
+        if (selector.startsWith('0x')) {
+            this.selector = selector;
+        } else {
+            this.selector = `$0x${selector}`;
+        }
+
+        // The selector must be 10 characters: '0x' followed by 4 bytes (two hex chars per byte)
+        if (this.selector.length !== 10) {
+            throw new Error(`Invalid selector '${this.selector}'`);
+        }
+        this.sizeInBytes += 8;
+    }
+}
+
+export class RawCalldata {
+    private value: Buffer;
+    private offset: number; // tracks current offset into raw calldata; used for parsing
+    private selector: string;
+    private scopes: Queue<number>;
+
+    constructor(value: string | Buffer) {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Expected raw calldata to start with '0x'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
+        this.value = valueBuf.slice(4); // disregard selector
+        this.offset = 0;
+        this.scopes = new Queue<number>();
+        this.scopes.push(0);
+    }
+
+    public popBytes(lengthInBytes: number): Buffer {
+        const value = this.value.slice(this.offset, this.offset + lengthInBytes);
+        this.setOffset(this.offset + lengthInBytes);
+        return value;
+    }
+
+    public popWord(): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(wordInBytes);
+    }
+
+    public popWords(length: number): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(length * wordInBytes);
+    }
+
+    public readBytes(from: number, to: number): Buffer {
+        const value = this.value.slice(from, to);
+        return value;
+    }
+
+    public setOffset(offsetInBytes: number) {
+        this.offset = offsetInBytes;
+    }
+
+    public startScope() {
+        this.scopes.pushFront(this.offset);
+    }
+
+    public endScope() {
+        this.scopes.pop();
+    }
+
+    public getOffset(): number {
+        return this.offset;
+    }
+
+    public toAbsoluteOffset(relativeOffset: number) {
+        const scopeOffset = this.scopes.peek();
+        if (scopeOffset === undefined) {
+            throw new Error(`Tried to access undefined scope.`);
+        }
+        const absoluteOffset = relativeOffset + scopeOffset;
+        return absoluteOffset;
+    }
+
+    public getSelector(): string {
+        return this.selector;
+    }
+}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder/data_type.ts b/packages/order-utils/test/abi_encoder/data_type.ts
new file mode 100644
index 000000000..4c4537a69
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder/data_type.ts
@@ -0,0 +1,322 @@
+import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
+import { MethodAbi, DataItem } from 'ethereum-types';
+import { DecodingRules, EncodingRules } from './calldata';
+import { BigNumber } from '@0x/utils';
+import ethUtil = require('ethereumjs-util');
+var _ = require('lodash');
+
+export interface DataTypeFactory {
+    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
+    mapDataItemToDataType: (dataItem: DataItem) => DataType;
+}
+
+export abstract class DataType {
+    private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
+    private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
+
+    private dataItem: DataItem;
+    private factory: DataTypeFactory;
+
+    constructor(dataItem: DataItem, factory: DataTypeFactory) {
+        this.dataItem = dataItem;
+        this.factory = factory;
+    }
+
+    public getDataItem(): DataItem {
+        return this.dataItem;
+    }
+
+    public getFactory(): DataTypeFactory {
+        return this.factory;
+    }
+
+    public encode(value: any, rules?: EncodingRules, selector?: string): string {
+        const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
+        const calldata = new Calldata(rules_);
+        if (selector) calldata.setSelector(selector);
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
+        const calldataHex = calldata.toHexString();
+        return calldataHex;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules): any {
+        const rawCalldata = new RawCalldata(calldata);
+        const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
+        const value = this.generateValue(rawCalldata, rules_);
+        return value;
+    }
+
+    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
+    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
+    public abstract getSignature(): string;
+    public abstract isStatic(): boolean;
+}
+
+export abstract class PayloadDataType extends DataType {
+    protected hasConstantSize: boolean;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+        super(dataItem, factory);
+        this.hasConstantSize = hasConstantSize;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
+        const encodedValue = this.encodeValue(value);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const relocatable = false;
+        const block = new PayloadCalldataBlock(name, signature, parentName, /*offsetInBytes,*/ relocatable, encodedValue);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const value = this.decodeValue(calldata);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        // If a payload has a constant size then it's static
+        return this.hasConstantSize;
+    }
+
+    public abstract encodeValue(value: any): Buffer;
+    public abstract decodeValue(calldata: RawCalldata): any;
+}
+
+export abstract class DependentDataType extends DataType {
+    protected dependency: DataType;
+    protected parent: DataType;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+        super(dataItem, factory);
+        this.dependency = dependency;
+        this.parent = parent;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
+        if (parentBlock === undefined) {
+            throw new Error(`DependentDataType requires a parent block to generate its block`);
+        }
+        const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const relocatable = false;
+        const block = new DependentCalldataBlock(name, signature, parentName, relocatable, dependencyBlock, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const destinationOffsetBuf = calldata.popWord();
+        const currentOffset = calldata.getOffset();
+        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
+        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
+        calldata.setOffset(destinationOffsetAbsolute);
+        const value = this.dependency.generateValue(calldata, rules);
+        calldata.setOffset(currentOffset);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+}
+
+export interface MemberMap {
+    [key: string]: number;
+}
+
+export abstract class MemberDataType extends DataType {
+    private memberMap: MemberMap;
+    private members: DataType[];
+    private isArray: boolean;
+    protected arrayLength: number | undefined;
+    protected arrayElementType: string | undefined;
+
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
+        super(dataItem, factory);
+        this.memberMap = {};
+        this.members = [];
+        this.isArray = isArray;
+        this.arrayLength = arrayLength;
+        this.arrayElementType = arrayElementType;
+        if (isArray && arrayLength !== undefined) {
+            [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
+        } else if (!isArray) {
+            [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
+        }
+    }
+
+    private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+        // Sanity check
+        if (dataItem.components === undefined) {
+            throw new Error(`Expected components`);
+        }
+
+        let members: DataType[] = [];
+        let memberMap: MemberMap = {};
+        _.each(dataItem.components, (memberItem: DataItem) => {
+            const childDataItem = {
+                type: memberItem.type,
+                name: `${dataItem.name}.${memberItem.name}`,
+            } as DataItem;
+            const components = memberItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[memberItem.name] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberMap];
+    }
+
+    private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        let members: DataType[] = [];
+        let memberMap: MemberMap = {};
+        const range = _.range(length);
+        _.each(range, (idx: number) => {
+            const childDataItem = {
+                type: this.arrayElementType,
+                name: `${dataItem.name}[${idx.toString(10)}]`,
+            } as DataItem;
+            const components = dataItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[idx.toString(10)] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberMap];
+    }
+
+    protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
+        // Sanity check length
+        if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
+            throw new Error(
+                `Expected array of ${JSON.stringify(
+                    this.arrayLength,
+                )} elements, but got array of length ${JSON.stringify(value.length)}`,
+            );
+        }
+
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
+
+        let members = this.members;
+        if (this.isArray && this.arrayLength === undefined) {
+            [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
+
+            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
+            methodBlock.setHeader(lenBuf);
+        }
+
+        const memberBlocks: CalldataBlock[] = [];
+        _.each(members, (member: DataType, idx: number) => {
+            const block = member.generateCalldataBlock(value[idx], methodBlock);
+            memberBlocks.push(block);
+        });
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
+    }
+
+    protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
+        const memberBlocks: CalldataBlock[] = [];
+        let childMap = _.cloneDeep(this.memberMap);
+        _.forOwn(obj, (value: any, key: string) => {
+            if (key in childMap === false) {
+                throw new Error(`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`);
+            }
+            const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
+            memberBlocks.push(block);
+            delete childMap[key];
+        });
+
+        if (Object.keys(childMap).length !== 0) {
+            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+        }
+
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
+    }
+
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value, parentBlock) : this.generateCalldataBlockFromObject(value, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
+        let members = this.members;
+        if (this.isArray && this.arrayLength === undefined) {
+            const arrayLengthBuf = calldata.popWord();
+            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+            const hexBase = 16;
+            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
+
+            [members,] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+        }
+
+        calldata.startScope();
+        let value: any[] | object;
+        if (rules.structsAsObjects && !this.isArray) {
+            value = {};
+            _.each(this.memberMap, (idx: number, key: string) => {
+                const member = this.members[idx];
+                let memberValue = member.generateValue(calldata, rules);
+                (value as { [key: string]: any })[key] = memberValue;
+            });
+        } else {
+            value = [];
+            _.each(members, (member: DataType, idx: number) => {
+                let memberValue = member.generateValue(calldata, rules);
+                (value as any[]).push(memberValue);
+            });
+        }
+        calldata.endScope();
+        return value;
+    }
+
+    protected computeSignatureOfMembers(): string {
+        // Compute signature of members
+        let signature = `(`;
+        _.each(this.members, (member: DataType, i: number) => {
+            signature += member.getSignature();
+            if (i < this.members.length - 1) {
+                signature += ',';
+            }
+        });
+        signature += ')';
+        return signature;
+    }
+
+    public isStatic(): boolean {
+        /* For Tuple:
+                    const isStaticTuple = this.children.length === 0;
+                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
+
+           For Array:
+                if isLengthDefined = false then this is false
+
+                Otherwise if the first element is a Pointer then false
+        */
+
+        if (this.isArray && this.arrayLength === undefined) {
+            return false;
+        }
+
+        // Search for dependent members
+        const dependentMember = _.find(this.members, (member: DataType) => {
+            return (member instanceof DependentDataType);
+        });
+        const isStatic = (dependentMember === undefined); // static if we couldn't find a dependent member
+        return isStatic;
+    }
+}
diff --git a/packages/order-utils/test/abi_encoder/evm_data_types.ts b/packages/order-utils/test/abi_encoder/evm_data_types.ts
new file mode 100644
index 000000000..bb7c1d81d
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder/evm_data_types.ts
@@ -0,0 +1,550 @@
+import { DataType, DataTypeFactory, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+
+import { DecodingRules, EncodingRules } from './calldata';
+
+import { MethodAbi, DataItem } from 'ethereum-types';
+
+import ethUtil = require('ethereumjs-util');
+
+import { Calldata, RawCalldata } from './calldata';
+
+import { BigNumber } from '@0x/utils';
+
+var _ = require('lodash');
+
+export interface DataTypeStaticInterface {
+    matchGrammar: (type: string) => boolean;
+    encodeValue: (value: any) => Buffer;
+    decodeValue: (rawCalldata: RawCalldata) => any;
+}
+
+export class Address extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Address.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'address';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'address';
+    }
+
+    public encodeValue(value: boolean): Buffer {
+        const evmWordWidth = 32;
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(12);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+}
+
+export class Bool extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bool.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bool.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'bool';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bool';
+    }
+
+    public encodeValue(value: boolean): Buffer {
+        const evmWordWidth = 32;
+        const encodedValue = value === true ? '0x1' : '0x0';
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): boolean {
+        const valueBuf = calldata.popWord();
+        const valueHex = ethUtil.bufferToHex(valueBuf);
+        const valueNumber = new BigNumber(valueHex, 16);
+        let value: boolean = (valueNumber.equals(0)) ? false : true;
+        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
+            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
+        }
+        return value;
+    }
+}
+
+abstract class Number extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    static MAX_WIDTH: number = 256;
+    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
+    width: number = Number.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem, matcher: RegExp) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Number.SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = matcher.exec(dataItem.type);
+        if (matches === null) {
+            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
+        }
+        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
+            this.width = parseInt(matches[1]);
+        } else {
+            this.width = 256;
+        }
+    }
+
+    public encodeValue(value: BigNumber): Buffer {
+        if (value.greaterThan(this.getMaxValue())) {
+            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+        } else if (value.lessThan(this.getMinValue())) {
+            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+        }
+
+        const hexBase = 16;
+        const evmWordWidth = 32;
+        let valueBuf: Buffer;
+        if (value.greaterThanOrEqualTo(0)) {
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
+        } else {
+            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
+            // Step 1/3: Convert value to positive binary string
+            const binBase = 2;
+            const valueBin = value.times(-1).toString(binBase);
+
+            // Step 2/3: Invert binary value
+            const bitsInEvmWord = 256;
+            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
+            _.each(valueBin, (bit: string) => {
+                invertedValueBin += bit === '1' ? '0' : '1';
+            });
+            const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+            // Step 3/3: Add 1 to inverted value
+            // The result is the two's-complement represent of the input value.
+            const negativeValue = invertedValue.plus(1);
+
+            // Convert the negated value to a hex string
+            valueBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
+                evmWordWidth,
+            );
+        }
+
+        return valueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): BigNumber {
+        const paddedValueBuf = calldata.popWord();
+        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
+        let value = new BigNumber(paddedValueHex, 16);
+        if (this instanceof Int) {
+            // Check if we're negative
+            const binBase = 2;
+            const paddedValueBin = value.toString(binBase);
+            const valueBin = paddedValueBin.slice(paddedValueBin.length - this.width);
+            if (valueBin[0].startsWith('1')) {
+                // Negative
+                // Step 1/3: Invert binary value
+                let invertedValueBin = '';
+                _.each(valueBin, (bit: string) => {
+                    invertedValueBin += bit === '1' ? '0' : '1';
+                });
+                const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+                // Step 2/3: Add 1 to inverted value
+                // The result is the two's-complement represent of the input value.
+                const positiveValue = invertedValue.plus(1);
+
+                // Step 3/3: Invert positive value
+                const negativeValue = positiveValue.times(-1);
+                value = negativeValue;
+            }
+        }
+
+        return value;
+    }
+
+    public abstract getMaxValue(): BigNumber;
+    public abstract getMinValue(): BigNumber;
+}
+
+export class Int extends Number {
+    static matcher = RegExp(
+        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Int.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).times(-1);
+    }
+
+    public getSignature(): string {
+        return `int${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class UInt extends Number {
+    static matcher = RegExp(
+        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, UInt.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getSignature(): string {
+        return `uint${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Byte extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    static matcher = RegExp(
+        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+    );
+
+    static DEFAULT_WIDTH = 1;
+    width: number = Byte.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Byte.SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = Byte.matcher.exec(dataItem.type);
+        if (!Byte.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
+        }
+        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
+            this.width = parseInt(matches[2]);
+        } else {
+            this.width = Byte.DEFAULT_WIDTH;
+        }
+    }
+
+    public getSignature(): string {
+        // Note that `byte` reduces to `bytes1`
+        return `bytes${this.width}`;
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        // Convert value into a buffer and do bounds checking
+        const valueBuf = ethUtil.toBuffer(value);
+        if (valueBuf.byteLength > this.width) {
+            throw new Error(
+                `Tried to assign ${value} (${
+                valueBuf.byteLength
+                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
+            );
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        // Store value as hex
+        const evmWordWidth = 32;
+        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
+        return paddedValue;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(0, this.width);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Bytes extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+    static UNDEFINED_LENGTH = new BigNumber(-1);
+    length: BigNumber = Bytes.UNDEFINED_LENGTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bytes.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
+        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
+        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, 16);
+        const wordsForValue = Math.ceil(length / 32);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const decodedValue = ethUtil.bufferToHex(valueBuf);
+        return decodedValue;
+    }
+
+    public getSignature(): string {
+        return 'bytes';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bytes';
+    }
+}
+
+export class SolString extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), SolString.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!SolString.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string): Buffer {
+        const wordsForValue = Math.ceil(value.length / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, 16);
+        const wordsForValue = Math.ceil(length / 32);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const value = valueBuf.toString('ascii');
+        return value;
+    }
+
+    public getSignature(): string {
+        return 'string';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'string';
+    }
+}
+
+export class Pointer extends DependentDataType {
+
+    constructor(destDataType: DataType, parentDataType: DataType) {
+        const destDataItem = destDataType.getDataItem();
+        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
+        super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
+    }
+
+    public getSignature(): string {
+        return this.dependency.getSignature();
+    }
+}
+
+export class Tuple extends MemberDataType {
+    private tupleSignature: string;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+        if (!Tuple.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
+        }
+        this.tupleSignature = this.computeSignatureOfMembers();
+    }
+
+    public getSignature(): string {
+        return this.tupleSignature;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'tuple';
+    }
+}
+
+export class SolArray extends MemberDataType {
+    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    private arraySignature: string;
+    private elementType: string;
+
+    constructor(dataItem: DataItem) {
+        // Sanity check
+        const matches = SolArray.matcher.exec(dataItem.type);
+        if (matches === null || matches.length !== 3) {
+            throw new Error(`Could not parse array: ${dataItem.type}`);
+        } else if (matches[1] === undefined) {
+            throw new Error(`Could not parse array type: ${dataItem.type}`);
+        } else if (matches[2] === undefined) {
+            throw new Error(`Could not parse array length: ${dataItem.type}`);
+        }
+
+        const isArray = true;
+        const arrayElementType = matches[1];
+        const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
+        super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
+        this.elementType = arrayElementType;
+        this.arraySignature = this.computeSignature();
+    }
+
+    private computeSignature(): string {
+        let dataItem = {
+            type: this.elementType,
+            name: 'N/A',
+        } as DataItem;
+        const components = this.getDataItem().components;
+        if (components !== undefined) {
+            dataItem.components = components;
+        }
+        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
+        const type = elementDataType.getSignature();
+        if (this.arrayLength === undefined) {
+            return `${type}[]`;
+        } else {
+            return `${type}[${this.arrayLength}]`;
+        }
+    }
+
+    public getSignature(): string {
+        return this.arraySignature;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Method extends MemberDataType {
+    private methodSignature: string;
+    private methodSelector: string;
+
+    // TMP
+    public selector: string;
+
+    constructor(abi: MethodAbi) {
+        super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
+        this.methodSignature = this.computeSignature();
+        this.selector = this.methodSelector = this.computeSelector();
+
+    }
+
+    private computeSignature(): string {
+        const memberSignature = this.computeSignatureOfMembers();
+        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
+        return methodSignature;
+    }
+
+    private computeSelector(): string {
+        const signature = this.computeSignature();
+        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(0, 4)));
+        return selector;
+    }
+
+    public encode(value: any, rules?: EncodingRules): string {
+        const calldata = super.encode(value, rules, this.selector);
+        return calldata;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules): any[] | object {
+        if (!calldata.startsWith(this.selector)) {
+            throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
+        }
+        const value = super.decode(calldata, rules);
+        return value;
+    }
+
+    public getSignature(): string {
+        return this.methodSignature;
+    }
+
+    public getSelector(): string {
+        return this.methodSelector;
+    }
+}
+
+export class EvmDataTypeFactory implements DataTypeFactory {
+    private static instance: DataTypeFactory;
+
+    private constructor() { }
+
+    public static getInstance(): DataTypeFactory {
+        if (!EvmDataTypeFactory.instance) {
+            EvmDataTypeFactory.instance = new EvmDataTypeFactory();
+        }
+        return EvmDataTypeFactory.instance;
+    }
+
+    public mapDataItemToDataType(dataItem: DataItem): DataType {
+        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
+        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
+        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
+        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
+        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
+        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
+        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
+        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
+        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
+        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
+
+        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+    }
+
+    public create(dataItem: DataItem, parentDataType: DataType): DataType {
+        const dataType = this.mapDataItemToDataType(dataItem);
+        if (dataType.isStatic()) {
+            return dataType;
+        }
+
+        const pointer = new Pointer(dataType, parentDataType);
+        return pointer;
+    }
+}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder/index.ts b/packages/order-utils/test/abi_encoder/index.ts
new file mode 100644
index 000000000..991edb8c5
--- /dev/null
+++ b/packages/order-utils/test/abi_encoder/index.ts
@@ -0,0 +1,2 @@
+export { EncodingRules, DecodingRules } from './calldata';
+export * from './evm_data_types';
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 295311acc..f1e562bc6 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -14,10 +14,9 @@ import { BigNumber } from '@0x/utils';
 import { assert } from '@0x/order-utils/src/assert';
 //import * as AbiEncoder from './abi_encoder';
 
-import * as AbiEncoder from './abi/abi_encoder';
+import * as AbiEncoder from './abi_encoder';
 
 import * as AbiSamples from './abi_samples';
-import { Calldata } from './abi/calldata';
 
 chaiSetup.configure();
 const expect = chai.expect;
@@ -42,7 +41,7 @@ describe.only('ABI Encoder', () => {
             // Verify optimized calldata is expected
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
 
             // Verify args decode properly
             const decodedArgs = method.decode(optimizedCalldata);
-- 
cgit v1.2.3


From 5b0d554f7baec54837d795b6568ae5ba8d8a0908 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 15:27:07 -0800
Subject: Moved Abi Encoder into utils package

---
 packages/order-utils/test/abi_encoder/calldata.ts  | 520 ------------
 packages/order-utils/test/abi_encoder/data_type.ts | 322 -------
 .../order-utils/test/abi_encoder/evm_data_types.ts | 550 ------------
 packages/order-utils/test/abi_encoder/index.ts     |   2 -
 packages/order-utils/test/abi_encoder_test.ts      | 943 ---------------------
 packages/order-utils/test/abi_samples.ts           | 814 ------------------
 packages/utils/src/abi_encoder/calldata.ts         | 520 ++++++++++++
 packages/utils/src/abi_encoder/data_type.ts        | 322 +++++++
 packages/utils/src/abi_encoder/evm_data_types.ts   | 550 ++++++++++++
 packages/utils/src/abi_encoder/index.ts            |   2 +
 packages/utils/src/index.ts                        |   1 +
 packages/utils/test/abi_encoder_test.ts            | 935 ++++++++++++++++++++
 packages/utils/test/abi_samples.ts                 | 814 ++++++++++++++++++
 packages/utils/test/utils/chai_setup.ts            |  13 +
 14 files changed, 3157 insertions(+), 3151 deletions(-)
 delete mode 100644 packages/order-utils/test/abi_encoder/calldata.ts
 delete mode 100644 packages/order-utils/test/abi_encoder/data_type.ts
 delete mode 100644 packages/order-utils/test/abi_encoder/evm_data_types.ts
 delete mode 100644 packages/order-utils/test/abi_encoder/index.ts
 delete mode 100644 packages/order-utils/test/abi_encoder_test.ts
 delete mode 100644 packages/order-utils/test/abi_samples.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata.ts
 create mode 100644 packages/utils/src/abi_encoder/data_type.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types.ts
 create mode 100644 packages/utils/src/abi_encoder/index.ts
 create mode 100644 packages/utils/test/abi_encoder_test.ts
 create mode 100644 packages/utils/test/abi_samples.ts
 create mode 100644 packages/utils/test/utils/chai_setup.ts

diff --git a/packages/order-utils/test/abi_encoder/calldata.ts b/packages/order-utils/test/abi_encoder/calldata.ts
deleted file mode 100644
index 32278e5c5..000000000
--- a/packages/order-utils/test/abi_encoder/calldata.ts
+++ /dev/null
@@ -1,520 +0,0 @@
-import ethUtil = require('ethereumjs-util');
-import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
-var _ = require('lodash');
-
-export interface DecodingRules {
-    structsAsObjects: boolean;
-}
-
-export interface EncodingRules {
-    optimize?: boolean;
-    annotate?: boolean;
-}
-
-export abstract class CalldataBlock {
-    private name: string;
-    private signature: string;
-    private offsetInBytes: number;
-    private headerSizeInBytes: number;
-    private bodySizeInBytes: number;
-    private relocatable: boolean;
-    private parentName: string;
-
-    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
-        this.name = name;
-        this.signature = signature;
-        this.parentName = parentName;
-        this.offsetInBytes = 0;
-        this.headerSizeInBytes = headerSizeInBytes;
-        this.bodySizeInBytes = bodySizeInBytes;
-        this.relocatable = relocatable;
-    }
-
-    protected setHeaderSize(headerSizeInBytes: number) {
-        this.headerSizeInBytes = headerSizeInBytes;
-    }
-
-    protected setBodySize(bodySizeInBytes: number) {
-        this.bodySizeInBytes = bodySizeInBytes;
-    }
-
-    protected setName(name: string) {
-        this.name = name;
-    }
-
-    public getName(): string {
-        return this.name;
-    }
-
-    public getParentName(): string {
-        return this.parentName;
-    }
-
-    public getSignature(): string {
-        return this.signature;
-    }
-
-    public isRelocatable(): boolean {
-        return this.relocatable;
-    }
-
-    public getHeaderSizeInBytes(): number {
-        return this.headerSizeInBytes;
-    }
-
-    public getBodySizeInBytes(): number {
-        return this.bodySizeInBytes;
-    }
-
-    public getSizeInBytes(): number {
-        return this.headerSizeInBytes + this.bodySizeInBytes;
-    }
-
-    public getOffsetInBytes(): number {
-        return this.offsetInBytes;
-    }
-
-    public setOffset(offsetInBytes: number) {
-        this.offsetInBytes = offsetInBytes;
-    }
-
-    public computeHash(): Buffer {
-        const rawData = this.getRawData();
-        const hash = ethUtil.sha3(rawData);
-        return hash;
-    }
-
-    public abstract toBuffer(): Buffer;
-    public abstract getRawData(): Buffer;
-}
-
-export class PayloadCalldataBlock extends CalldataBlock {
-    private payload: Buffer;
-
-    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = payload.byteLength;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
-        this.payload = payload;
-    }
-
-    public toBuffer(): Buffer {
-        return this.payload;
-    }
-
-    public getRawData(): Buffer {
-        return this.payload;
-    }
-}
-
-export class DependentCalldataBlock extends CalldataBlock {
-    public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    public static RAW_DATA_START = new Buffer('<');
-    public static RAW_DATA_END = new Buffer('>');
-    private parent: CalldataBlock;
-    private dependency: CalldataBlock;
-    private aliasFor: CalldataBlock | undefined;
-
-    constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
-        this.parent = parent;
-        this.dependency = dependency;
-        this.aliasFor = undefined;
-    }
-
-    public toBuffer(): Buffer {
-        const destinationOffset = (this.aliasFor !== undefined) ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
-        const parentOffset = this.parent.getOffsetInBytes();
-        const parentHeaderSize = this.parent.getHeaderSizeInBytes();
-        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
-        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
-        const evmWordWidthInBytes = 32;
-        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
-        return pointerBufPadded;
-    }
-
-    public getDependency(): CalldataBlock {
-        return this.dependency;
-    }
-
-    public setAlias(block: CalldataBlock) {
-        this.aliasFor = block;
-        this.setName(`${this.getName()} (alias for ${block.getName()})`);
-    }
-
-    public getAlias(): CalldataBlock | undefined {
-        return this.aliasFor;
-    }
-
-    public getRawData(): Buffer {
-        const dependencyRawData = this.dependency.getRawData();
-        const rawDataComponents: Buffer[] = [];
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
-        rawDataComponents.push(dependencyRawData);
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-}
-
-export class MemberCalldataBlock extends CalldataBlock {
-    private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    private header: Buffer | undefined;
-    private members: CalldataBlock[];
-    private contiguous: boolean;
-
-    constructor(name: string, signature: string, parentName: string, relocatable: boolean, contiguous: boolean) {
-        super(name, signature, parentName, 0, 0, relocatable);
-        this.members = [];
-        this.header = undefined;
-        this.contiguous = contiguous;
-    }
-
-    public getRawData(): Buffer {
-        const rawDataComponents: Buffer[] = [];
-        if (this.header !== undefined) {
-            rawDataComponents.push(this.header);
-        }
-        _.each(this.members, (member: CalldataBlock) => {
-            const memberBuffer = member.getRawData();
-            rawDataComponents.push(memberBuffer);
-        });
-
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-
-    public setMembers(members: CalldataBlock[]) {
-        let bodySizeInBytes = 0;
-        _.each(members, (member: CalldataBlock) => {
-            bodySizeInBytes += member.getSizeInBytes();
-        });
-        this.members = members;
-        this.setBodySize(0);
-    }
-
-    public isContiguous(): boolean {
-        return true;
-    }
-
-    public setHeader(header: Buffer) {
-        this.setHeaderSize(header.byteLength);
-        this.header = header;
-    }
-
-    public toBuffer(): Buffer {
-        if (this.header !== undefined) return this.header;
-        return new Buffer('');
-    }
-
-    public getMembers(): CalldataBlock[] {
-        return this.members;
-    }
-}
-
-class Queue<T> {
-    private store: T[] = [];
-    push(val: T) {
-        this.store.push(val);
-    }
-    pushFront(val: T) {
-        this.store.unshift(val);
-    }
-    pop(): T | undefined {
-        return this.store.shift();
-    }
-    popBack(): T | undefined {
-        if (this.store.length === 0) return undefined;
-        const backElement = this.store.splice(-1, 1)[0];
-        return backElement;
-    }
-    merge(q: Queue<T>) {
-        this.store = this.store.concat(q.store);
-    }
-    mergeFront(q: Queue<T>) {
-        this.store = q.store.concat(this.store);
-    }
-    getStore(): T[] {
-        return this.store;
-    }
-    peek(): T | undefined {
-        return this.store.length >= 0 ? this.store[0] : undefined;
-    }
-}
-
-export class Calldata {
-    private selector: string;
-    private rules: EncodingRules;
-    private sizeInBytes: number;
-    private root: MemberCalldataBlock | undefined;
-
-    constructor(rules: EncodingRules) {
-        this.selector = '';
-        this.rules = rules;
-        this.sizeInBytes = 0;
-        this.root = undefined;
-    }
-
-    private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> {
-        const blockQueue = new Queue<CalldataBlock>();
-        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof MemberCalldataBlock) {
-                blockQueue.mergeFront(this.createQueue(member));
-            } else {
-                blockQueue.pushFront(member);
-            }
-        });
-
-        // Children
-        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
-                let dependency = member.getDependency();
-                if (dependency instanceof MemberCalldataBlock) {
-                    blockQueue.merge(this.createQueue(dependency));
-                } else {
-                    blockQueue.push(dependency);
-                }
-            }
-        });
-
-        blockQueue.pushFront(memberBlock);
-        return blockQueue;
-    }
-
-    private generateAnnotatedHexString(): string {
-        let hexValue = `${this.selector}`;
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = this.createQueue(this.root);
-
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        const functionBlock = valueQueue.peek();
-        let functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
-        while ((block = valueQueue.pop()) !== undefined) {
-            // Set f
-
-            // Process each block 1 word at a time
-            const size = block.getSizeInBytes();
-            const name = block.getName();
-            const parentName = block.getParentName();
-
-            //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
-            //const parentOffset = name.lastIndexOf(parentName);
-            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');//.replace(`${parentName}[`, '[');
-            const signature = block.getSignature();
-
-            // Current offset
-            let offsetStr = '';
-
-            // If this block is empty then it's a newline
-            let value = '';
-            let nameStr = '';
-            let line = '';
-            if (size === 0) {
-                offsetStr = ' '.repeat(10);
-                value = ' '.repeat(74);
-                nameStr = `### ${prettyName.padEnd(80)}`;
-                line = `\n${offsetStr}${value}${nameStr}`;
-            } else {
-                offsetStr = `0x${offset.toString(16)}`.padEnd(10, ' ');
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(0, 32))).padEnd(74);
-                if (block instanceof MemberCalldataBlock) {
-                    nameStr = `### ${prettyName.padEnd(80)}`;
-                    line = `\n${offsetStr}${value}${nameStr}`;
-                } else {
-                    nameStr = `    ${prettyName.padEnd(80)}`;
-                    line = `${offsetStr}${value}${nameStr}`;
-                }
-            }
-
-            for (let j = 32; j < size; j += 32) {
-                offsetStr = `0x${(offset + j).toString(16)}`.padEnd(10, ' ');
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + 32))).padEnd(74);
-                nameStr = ' '.repeat(40);
-
-                line = `${line}\n${offsetStr}${value}${nameStr}`;
-            }
-
-            // Append to hex value
-            hexValue = `${hexValue}\n${line}`;
-            offset += size;
-        }
-
-        return hexValue;
-    }
-
-    private generateCondensedHexString(): string {
-        let selectorBuffer = ethUtil.toBuffer(this.selector);
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = this.createQueue(this.root);
-        const valueBufs: Buffer[] = [selectorBuffer];
-        let block: CalldataBlock | undefined;
-        while ((block = valueQueue.pop()) !== undefined) {
-            valueBufs.push(block.toBuffer());
-        }
-
-        const combinedBuffers = Buffer.concat(valueBufs);
-        const hexValue = ethUtil.bufferToHex(combinedBuffers);
-        return hexValue;
-    }
-
-    public optimize() {
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const blocksByHash: { [key: string]: CalldataBlock } = {};
-
-        // 1. Create a queue of subtrees by hash
-        // Note that they are ordered the same as 
-        const subtreeQueue = this.createQueue(this.root);
-        let block: CalldataBlock | undefined;
-        while ((block = subtreeQueue.popBack()) !== undefined) {
-            if (block instanceof DependentCalldataBlock) {
-                const blockHashBuf = block.getDependency().computeHash();
-                const blockHash = ethUtil.bufferToHex(blockHashBuf);
-                if (blockHash in blocksByHash) {
-                    const blockWithSameHash = blocksByHash[blockHash];
-                    if (blockWithSameHash !== block.getDependency()) {
-                        block.setAlias(blockWithSameHash);
-                    }
-                }
-                continue;
-            }
-
-            const blockHashBuf = block.computeHash();
-            const blockHash = ethUtil.bufferToHex(blockHashBuf);
-            if (blockHash in blocksByHash === false) {
-                blocksByHash[blockHash] = block;
-            }
-        }
-    }
-
-    public toHexString(): string {
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        if (this.rules.optimize) this.optimize();
-
-        const offsetQueue = this.createQueue(this.root);
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        while ((block = offsetQueue.pop()) !== undefined) {
-            block.setOffset(offset);
-            offset += block.getSizeInBytes();
-        }
-
-        const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
-        return hexValue;
-    }
-
-    public getSelectorHex(): string {
-        return this.selector;
-    }
-
-    public getSizeInBytes(): number {
-        return this.sizeInBytes;
-    }
-
-    public toAnnotatedString(): string {
-        return "";
-    }
-
-    public setRoot(block: MemberCalldataBlock) {
-        this.root = block;
-        this.sizeInBytes += block.getSizeInBytes();
-    }
-
-    public setSelector(selector: string) {
-        // Ensure we have a 0x prefix
-        if (selector.startsWith('0x')) {
-            this.selector = selector;
-        } else {
-            this.selector = `$0x${selector}`;
-        }
-
-        // The selector must be 10 characters: '0x' followed by 4 bytes (two hex chars per byte)
-        if (this.selector.length !== 10) {
-            throw new Error(`Invalid selector '${this.selector}'`);
-        }
-        this.sizeInBytes += 8;
-    }
-}
-
-export class RawCalldata {
-    private value: Buffer;
-    private offset: number; // tracks current offset into raw calldata; used for parsing
-    private selector: string;
-    private scopes: Queue<number>;
-
-    constructor(value: string | Buffer) {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Expected raw calldata to start with '0x'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
-        this.value = valueBuf.slice(4); // disregard selector
-        this.offset = 0;
-        this.scopes = new Queue<number>();
-        this.scopes.push(0);
-    }
-
-    public popBytes(lengthInBytes: number): Buffer {
-        const value = this.value.slice(this.offset, this.offset + lengthInBytes);
-        this.setOffset(this.offset + lengthInBytes);
-        return value;
-    }
-
-    public popWord(): Buffer {
-        const wordInBytes = 32;
-        return this.popBytes(wordInBytes);
-    }
-
-    public popWords(length: number): Buffer {
-        const wordInBytes = 32;
-        return this.popBytes(length * wordInBytes);
-    }
-
-    public readBytes(from: number, to: number): Buffer {
-        const value = this.value.slice(from, to);
-        return value;
-    }
-
-    public setOffset(offsetInBytes: number) {
-        this.offset = offsetInBytes;
-    }
-
-    public startScope() {
-        this.scopes.pushFront(this.offset);
-    }
-
-    public endScope() {
-        this.scopes.pop();
-    }
-
-    public getOffset(): number {
-        return this.offset;
-    }
-
-    public toAbsoluteOffset(relativeOffset: number) {
-        const scopeOffset = this.scopes.peek();
-        if (scopeOffset === undefined) {
-            throw new Error(`Tried to access undefined scope.`);
-        }
-        const absoluteOffset = relativeOffset + scopeOffset;
-        return absoluteOffset;
-    }
-
-    public getSelector(): string {
-        return this.selector;
-    }
-}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder/data_type.ts b/packages/order-utils/test/abi_encoder/data_type.ts
deleted file mode 100644
index 4c4537a69..000000000
--- a/packages/order-utils/test/abi_encoder/data_type.ts
+++ /dev/null
@@ -1,322 +0,0 @@
-import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
-import { MethodAbi, DataItem } from 'ethereum-types';
-import { DecodingRules, EncodingRules } from './calldata';
-import { BigNumber } from '@0x/utils';
-import ethUtil = require('ethereumjs-util');
-var _ = require('lodash');
-
-export interface DataTypeFactory {
-    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
-    mapDataItemToDataType: (dataItem: DataItem) => DataType;
-}
-
-export abstract class DataType {
-    private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
-    private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
-
-    private dataItem: DataItem;
-    private factory: DataTypeFactory;
-
-    constructor(dataItem: DataItem, factory: DataTypeFactory) {
-        this.dataItem = dataItem;
-        this.factory = factory;
-    }
-
-    public getDataItem(): DataItem {
-        return this.dataItem;
-    }
-
-    public getFactory(): DataTypeFactory {
-        return this.factory;
-    }
-
-    public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
-        const calldata = new Calldata(rules_);
-        if (selector) calldata.setSelector(selector);
-        const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
-        const calldataHex = calldata.toHexString();
-        return calldataHex;
-    }
-
-    public decode(calldata: string, rules?: DecodingRules): any {
-        const rawCalldata = new RawCalldata(calldata);
-        const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
-        const value = this.generateValue(rawCalldata, rules_);
-        return value;
-    }
-
-    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
-    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
-    public abstract getSignature(): string;
-    public abstract isStatic(): boolean;
-}
-
-export abstract class PayloadDataType extends DataType {
-    protected hasConstantSize: boolean;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
-        super(dataItem, factory);
-        this.hasConstantSize = hasConstantSize;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
-        const encodedValue = this.encodeValue(value);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const relocatable = false;
-        const block = new PayloadCalldataBlock(name, signature, parentName, /*offsetInBytes,*/ relocatable, encodedValue);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const value = this.decodeValue(calldata);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        // If a payload has a constant size then it's static
-        return this.hasConstantSize;
-    }
-
-    public abstract encodeValue(value: any): Buffer;
-    public abstract decodeValue(calldata: RawCalldata): any;
-}
-
-export abstract class DependentDataType extends DataType {
-    protected dependency: DataType;
-    protected parent: DataType;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
-        super(dataItem, factory);
-        this.dependency = dependency;
-        this.parent = parent;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
-        if (parentBlock === undefined) {
-            throw new Error(`DependentDataType requires a parent block to generate its block`);
-        }
-        const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const relocatable = false;
-        const block = new DependentCalldataBlock(name, signature, parentName, relocatable, dependencyBlock, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const destinationOffsetBuf = calldata.popWord();
-        const currentOffset = calldata.getOffset();
-        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
-        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
-        calldata.setOffset(destinationOffsetAbsolute);
-        const value = this.dependency.generateValue(calldata, rules);
-        calldata.setOffset(currentOffset);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        return true;
-    }
-}
-
-export interface MemberMap {
-    [key: string]: number;
-}
-
-export abstract class MemberDataType extends DataType {
-    private memberMap: MemberMap;
-    private members: DataType[];
-    private isArray: boolean;
-    protected arrayLength: number | undefined;
-    protected arrayElementType: string | undefined;
-
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
-        super(dataItem, factory);
-        this.memberMap = {};
-        this.members = [];
-        this.isArray = isArray;
-        this.arrayLength = arrayLength;
-        this.arrayElementType = arrayElementType;
-        if (isArray && arrayLength !== undefined) {
-            [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
-        } else if (!isArray) {
-            [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
-        }
-    }
-
-    private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
-        // Sanity check
-        if (dataItem.components === undefined) {
-            throw new Error(`Expected components`);
-        }
-
-        let members: DataType[] = [];
-        let memberMap: MemberMap = {};
-        _.each(dataItem.components, (memberItem: DataItem) => {
-            const childDataItem = {
-                type: memberItem.type,
-                name: `${dataItem.name}.${memberItem.name}`,
-            } as DataItem;
-            const components = memberItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[memberItem.name] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberMap];
-    }
-
-    private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
-        let members: DataType[] = [];
-        let memberMap: MemberMap = {};
-        const range = _.range(length);
-        _.each(range, (idx: number) => {
-            const childDataItem = {
-                type: this.arrayElementType,
-                name: `${dataItem.name}[${idx.toString(10)}]`,
-            } as DataItem;
-            const components = dataItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[idx.toString(10)] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberMap];
-    }
-
-    protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
-        // Sanity check length
-        if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
-            throw new Error(
-                `Expected array of ${JSON.stringify(
-                    this.arrayLength,
-                )} elements, but got array of length ${JSON.stringify(value.length)}`,
-            );
-        }
-
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
-
-        let members = this.members;
-        if (this.isArray && this.arrayLength === undefined) {
-            [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
-
-            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
-            methodBlock.setHeader(lenBuf);
-        }
-
-        const memberBlocks: CalldataBlock[] = [];
-        _.each(members, (member: DataType, idx: number) => {
-            const block = member.generateCalldataBlock(value[idx], methodBlock);
-            memberBlocks.push(block);
-        });
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
-        const memberBlocks: CalldataBlock[] = [];
-        let childMap = _.cloneDeep(this.memberMap);
-        _.forOwn(obj, (value: any, key: string) => {
-            if (key in childMap === false) {
-                throw new Error(`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`);
-            }
-            const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
-            memberBlocks.push(block);
-            delete childMap[key];
-        });
-
-        if (Object.keys(childMap).length !== 0) {
-            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
-        }
-
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value, parentBlock) : this.generateCalldataBlockFromObject(value, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
-        let members = this.members;
-        if (this.isArray && this.arrayLength === undefined) {
-            const arrayLengthBuf = calldata.popWord();
-            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const hexBase = 16;
-            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
-            [members,] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
-        }
-
-        calldata.startScope();
-        let value: any[] | object;
-        if (rules.structsAsObjects && !this.isArray) {
-            value = {};
-            _.each(this.memberMap, (idx: number, key: string) => {
-                const member = this.members[idx];
-                let memberValue = member.generateValue(calldata, rules);
-                (value as { [key: string]: any })[key] = memberValue;
-            });
-        } else {
-            value = [];
-            _.each(members, (member: DataType, idx: number) => {
-                let memberValue = member.generateValue(calldata, rules);
-                (value as any[]).push(memberValue);
-            });
-        }
-        calldata.endScope();
-        return value;
-    }
-
-    protected computeSignatureOfMembers(): string {
-        // Compute signature of members
-        let signature = `(`;
-        _.each(this.members, (member: DataType, i: number) => {
-            signature += member.getSignature();
-            if (i < this.members.length - 1) {
-                signature += ',';
-            }
-        });
-        signature += ')';
-        return signature;
-    }
-
-    public isStatic(): boolean {
-        /* For Tuple:
-                    const isStaticTuple = this.children.length === 0;
-                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
-           For Array:
-                if isLengthDefined = false then this is false
-
-                Otherwise if the first element is a Pointer then false
-        */
-
-        if (this.isArray && this.arrayLength === undefined) {
-            return false;
-        }
-
-        // Search for dependent members
-        const dependentMember = _.find(this.members, (member: DataType) => {
-            return (member instanceof DependentDataType);
-        });
-        const isStatic = (dependentMember === undefined); // static if we couldn't find a dependent member
-        return isStatic;
-    }
-}
diff --git a/packages/order-utils/test/abi_encoder/evm_data_types.ts b/packages/order-utils/test/abi_encoder/evm_data_types.ts
deleted file mode 100644
index bb7c1d81d..000000000
--- a/packages/order-utils/test/abi_encoder/evm_data_types.ts
+++ /dev/null
@@ -1,550 +0,0 @@
-import { DataType, DataTypeFactory, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
-
-import { DecodingRules, EncodingRules } from './calldata';
-
-import { MethodAbi, DataItem } from 'ethereum-types';
-
-import ethUtil = require('ethereumjs-util');
-
-import { Calldata, RawCalldata } from './calldata';
-
-import { BigNumber } from '@0x/utils';
-
-var _ = require('lodash');
-
-export interface DataTypeStaticInterface {
-    matchGrammar: (type: string) => boolean;
-    encodeValue: (value: any) => Buffer;
-    decodeValue: (rawCalldata: RawCalldata) => any;
-}
-
-export class Address extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Address.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
-        }
-    }
-
-    public getSignature(): string {
-        return 'address';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'address';
-    }
-
-    public encodeValue(value: boolean): Buffer {
-        const evmWordWidth = 32;
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(12);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
-    }
-}
-
-export class Bool extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bool.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bool.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
-        }
-    }
-
-    public getSignature(): string {
-        return 'bool';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'bool';
-    }
-
-    public encodeValue(value: boolean): Buffer {
-        const evmWordWidth = 32;
-        const encodedValue = value === true ? '0x1' : '0x0';
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): boolean {
-        const valueBuf = calldata.popWord();
-        const valueHex = ethUtil.bufferToHex(valueBuf);
-        const valueNumber = new BigNumber(valueHex, 16);
-        let value: boolean = (valueNumber.equals(0)) ? false : true;
-        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
-            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
-        }
-        return value;
-    }
-}
-
-abstract class Number extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    static MAX_WIDTH: number = 256;
-    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
-    width: number = Number.DEFAULT_WIDTH;
-
-    constructor(dataItem: DataItem, matcher: RegExp) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Number.SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = matcher.exec(dataItem.type);
-        if (matches === null) {
-            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
-        }
-        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
-            this.width = parseInt(matches[1]);
-        } else {
-            this.width = 256;
-        }
-    }
-
-    public encodeValue(value: BigNumber): Buffer {
-        if (value.greaterThan(this.getMaxValue())) {
-            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
-        } else if (value.lessThan(this.getMinValue())) {
-            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
-        }
-
-        const hexBase = 16;
-        const evmWordWidth = 32;
-        let valueBuf: Buffer;
-        if (value.greaterThanOrEqualTo(0)) {
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
-        } else {
-            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
-            // Step 1/3: Convert value to positive binary string
-            const binBase = 2;
-            const valueBin = value.times(-1).toString(binBase);
-
-            // Step 2/3: Invert binary value
-            const bitsInEvmWord = 256;
-            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
-            _.each(valueBin, (bit: string) => {
-                invertedValueBin += bit === '1' ? '0' : '1';
-            });
-            const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-            // Step 3/3: Add 1 to inverted value
-            // The result is the two's-complement represent of the input value.
-            const negativeValue = invertedValue.plus(1);
-
-            // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
-                evmWordWidth,
-            );
-        }
-
-        return valueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): BigNumber {
-        const paddedValueBuf = calldata.popWord();
-        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
-        let value = new BigNumber(paddedValueHex, 16);
-        if (this instanceof Int) {
-            // Check if we're negative
-            const binBase = 2;
-            const paddedValueBin = value.toString(binBase);
-            const valueBin = paddedValueBin.slice(paddedValueBin.length - this.width);
-            if (valueBin[0].startsWith('1')) {
-                // Negative
-                // Step 1/3: Invert binary value
-                let invertedValueBin = '';
-                _.each(valueBin, (bit: string) => {
-                    invertedValueBin += bit === '1' ? '0' : '1';
-                });
-                const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-                // Step 2/3: Add 1 to inverted value
-                // The result is the two's-complement represent of the input value.
-                const positiveValue = invertedValue.plus(1);
-
-                // Step 3/3: Invert positive value
-                const negativeValue = positiveValue.times(-1);
-                value = negativeValue;
-            }
-        }
-
-        return value;
-    }
-
-    public abstract getMaxValue(): BigNumber;
-    public abstract getMinValue(): BigNumber;
-}
-
-export class Int extends Number {
-    static matcher = RegExp(
-        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, Int.matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).times(-1);
-    }
-
-    public getSignature(): string {
-        return `int${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class UInt extends Number {
-    static matcher = RegExp(
-        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, UInt.matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getSignature(): string {
-        return `uint${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Byte extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    static matcher = RegExp(
-        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
-    );
-
-    static DEFAULT_WIDTH = 1;
-    width: number = Byte.DEFAULT_WIDTH;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Byte.SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = Byte.matcher.exec(dataItem.type);
-        if (!Byte.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
-        }
-        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
-            this.width = parseInt(matches[2]);
-        } else {
-            this.width = Byte.DEFAULT_WIDTH;
-        }
-    }
-
-    public getSignature(): string {
-        // Note that `byte` reduces to `bytes1`
-        return `bytes${this.width}`;
-    }
-
-    public encodeValue(value: string | Buffer): Buffer {
-        // Convert value into a buffer and do bounds checking
-        const valueBuf = ethUtil.toBuffer(value);
-        if (valueBuf.byteLength > this.width) {
-            throw new Error(
-                `Tried to assign ${value} (${
-                valueBuf.byteLength
-                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
-            );
-        } else if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        // Store value as hex
-        const evmWordWidth = 32;
-        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
-        return paddedValue;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(0, this.width);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Bytes extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-    static UNDEFINED_LENGTH = new BigNumber(-1);
-    length: BigNumber = Bytes.UNDEFINED_LENGTH;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bytes.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
-        }
-    }
-
-    public encodeValue(value: string | Buffer): Buffer {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
-        const paddedBytesForValue = wordsForValue * 32;
-        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
-        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
-        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, 16);
-        const wordsForValue = Math.ceil(length / 32);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const decodedValue = ethUtil.bufferToHex(valueBuf);
-        return decodedValue;
-    }
-
-    public getSignature(): string {
-        return 'bytes';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'bytes';
-    }
-}
-
-export class SolString extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), SolString.SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!SolString.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
-        }
-    }
-
-    public encodeValue(value: string): Buffer {
-        const wordsForValue = Math.ceil(value.length / 32);
-        const paddedBytesForValue = wordsForValue * 32;
-        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
-        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
-        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, 16);
-        const wordsForValue = Math.ceil(length / 32);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const value = valueBuf.toString('ascii');
-        return value;
-    }
-
-    public getSignature(): string {
-        return 'string';
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'string';
-    }
-}
-
-export class Pointer extends DependentDataType {
-
-    constructor(destDataType: DataType, parentDataType: DataType) {
-        const destDataItem = destDataType.getDataItem();
-        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
-        super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
-    }
-
-    public getSignature(): string {
-        return this.dependency.getSignature();
-    }
-}
-
-export class Tuple extends MemberDataType {
-    private tupleSignature: string;
-
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance());
-        if (!Tuple.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
-        }
-        this.tupleSignature = this.computeSignatureOfMembers();
-    }
-
-    public getSignature(): string {
-        return this.tupleSignature;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'tuple';
-    }
-}
-
-export class SolArray extends MemberDataType {
-    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
-    private arraySignature: string;
-    private elementType: string;
-
-    constructor(dataItem: DataItem) {
-        // Sanity check
-        const matches = SolArray.matcher.exec(dataItem.type);
-        if (matches === null || matches.length !== 3) {
-            throw new Error(`Could not parse array: ${dataItem.type}`);
-        } else if (matches[1] === undefined) {
-            throw new Error(`Could not parse array type: ${dataItem.type}`);
-        } else if (matches[2] === undefined) {
-            throw new Error(`Could not parse array length: ${dataItem.type}`);
-        }
-
-        const isArray = true;
-        const arrayElementType = matches[1];
-        const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
-        super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
-        this.elementType = arrayElementType;
-        this.arraySignature = this.computeSignature();
-    }
-
-    private computeSignature(): string {
-        let dataItem = {
-            type: this.elementType,
-            name: 'N/A',
-        } as DataItem;
-        const components = this.getDataItem().components;
-        if (components !== undefined) {
-            dataItem.components = components;
-        }
-        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
-        const type = elementDataType.getSignature();
-        if (this.arrayLength === undefined) {
-            return `${type}[]`;
-        } else {
-            return `${type}[${this.arrayLength}]`;
-        }
-    }
-
-    public getSignature(): string {
-        return this.arraySignature;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
-}
-
-export class Method extends MemberDataType {
-    private methodSignature: string;
-    private methodSelector: string;
-
-    // TMP
-    public selector: string;
-
-    constructor(abi: MethodAbi) {
-        super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
-        this.methodSignature = this.computeSignature();
-        this.selector = this.methodSelector = this.computeSelector();
-
-    }
-
-    private computeSignature(): string {
-        const memberSignature = this.computeSignatureOfMembers();
-        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
-        return methodSignature;
-    }
-
-    private computeSelector(): string {
-        const signature = this.computeSignature();
-        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(0, 4)));
-        return selector;
-    }
-
-    public encode(value: any, rules?: EncodingRules): string {
-        const calldata = super.encode(value, rules, this.selector);
-        return calldata;
-    }
-
-    public decode(calldata: string, rules?: DecodingRules): any[] | object {
-        if (!calldata.startsWith(this.selector)) {
-            throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
-        }
-        const value = super.decode(calldata, rules);
-        return value;
-    }
-
-    public getSignature(): string {
-        return this.methodSignature;
-    }
-
-    public getSelector(): string {
-        return this.methodSelector;
-    }
-}
-
-export class EvmDataTypeFactory implements DataTypeFactory {
-    private static instance: DataTypeFactory;
-
-    private constructor() { }
-
-    public static getInstance(): DataTypeFactory {
-        if (!EvmDataTypeFactory.instance) {
-            EvmDataTypeFactory.instance = new EvmDataTypeFactory();
-        }
-        return EvmDataTypeFactory.instance;
-    }
-
-    public mapDataItemToDataType(dataItem: DataItem): DataType {
-        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
-        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
-        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
-        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
-        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
-        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
-        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
-        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
-        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
-
-        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-    }
-
-    public create(dataItem: DataItem, parentDataType: DataType): DataType {
-        const dataType = this.mapDataItemToDataType(dataItem);
-        if (dataType.isStatic()) {
-            return dataType;
-        }
-
-        const pointer = new Pointer(dataType, parentDataType);
-        return pointer;
-    }
-}
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder/index.ts b/packages/order-utils/test/abi_encoder/index.ts
deleted file mode 100644
index 991edb8c5..000000000
--- a/packages/order-utils/test/abi_encoder/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { EncodingRules, DecodingRules } from './calldata';
-export * from './evm_data_types';
\ No newline at end of file
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
deleted file mode 100644
index f1e562bc6..000000000
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ /dev/null
@@ -1,943 +0,0 @@
-import * as chai from 'chai';
-import 'mocha';
-import ethUtil = require('ethereumjs-util');
-
-var _ = require('lodash');
-
-// import { assert } from '@0x/order-utils/src/assert';
-
-import { chaiSetup } from './utils/chai_setup';
-
-import { MethodAbi, DataItem } from 'ethereum-types';
-
-import { BigNumber } from '@0x/utils';
-import { assert } from '@0x/order-utils/src/assert';
-//import * as AbiEncoder from './abi_encoder';
-
-import * as AbiEncoder from './abi_encoder';
-
-import * as AbiSamples from './abi_samples';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe.only('ABI Encoder', () => {
-    describe.only('Optimizer', () => {
-
-    });
-
-    describe.only('ABI Tests at Method Level', () => {
-
-        it('Should reuse duplicated strings in string array', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
-            const strings = [
-                "Test String",
-                "Test String 2",
-                "Test String",
-                "Test String 2",
-            ];
-            const args = [strings];
-
-            // Verify optimized calldata is expected
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
-            //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-
-            // Verify args decode properly
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
-        });
-
-        it('Should point array elements to a duplicated value from another parameter', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
-            const stringArray = [
-                "Test String",
-                "Test String",
-                "Test String",
-                "Test String 2",
-            ];
-            const string = 'Test String';
-            const args = [stringArray, string];
-
-            // Verify optimized calldata is expected
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata = '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-
-            // Verify args decode properly
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
-        });
-
-
-        it('Optimizer #3 (tuple should point to array)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi3);
-            const uint8Array = [
-                new BigNumber(100),
-                new BigNumber(150),
-                new BigNumber(200),
-                new BigNumber(225),
-            ];
-            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
-            const args = [uint8Array, uintTupleArray];
-
-
-            const TEST = method.encode(args, { optimize: true, annotate: true });
-            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
-
-            const optimizedCalldata = method.encode(args, { optimize: true });
-
-            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            console.log(JSON.stringify(decodedArgs));
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-
-        it('Optimizer #4 (Expect no optimization)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
-            const uint8Array = [
-                new BigNumber(100),
-                new BigNumber(150),
-                new BigNumber(200),
-                new BigNumber(225),
-            ];
-            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
-            const args = [uint8Array, uintTupleArray];
-
-
-            const TEST = method.encode(args, { optimize: true, annotate: true });
-            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
-
-            const optimizedCalldata = method.encode(args, { optimize: true });
-
-            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            console.log(JSON.stringify(decodedArgs));
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-
-        it('Crazy ABI', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
-            console.log(method.getSignature());
-
-            const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
-            const someStaticArrayWithDynamicMembers = [
-                'the little piping piper piped a piping pipper papper',
-                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-            ];
-            const someDynamicArrayWithDynamicMembers = [
-                '0x38745637834987324827439287423897238947239847',
-                '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
-                '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
-            ];
-            const some2DArray = [
-                [
-                    'some string',
-                    'some another string',
-                    'there are just too many stringsup in',
-                    'here',
-                    'yall ghonna make me lose my mind',
-                ],
-                [
-                    'the little piping piper piped a piping pipper papper',
-                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-                ],
-                [],
-            ];
-            const someTuple = {
-                someUint32: new BigNumber(4037824789),
-                someStr: 'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.'
-            };
-            const someTupleWithDynamicTypes = {
-                someUint: new BigNumber(4024789),
-                someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
-                someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
-                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
-            };
-            const someTupleWithDynamicTypes2 = {
-                someUint: new BigNumber(9024789),
-                someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
-                someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
-                someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
-            };
-            const someTupleWithDynamicTypes3 = {
-                someUint: new BigNumber(1024789),
-                someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
-                someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
-                someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
-            };
-            const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
-
-            const args = {
-                someStaticArray: someStaticArray,
-                someStaticArrayWithDynamicMembers: someStaticArrayWithDynamicMembers,
-                someDynamicArrayWithDynamicMembers: someDynamicArrayWithDynamicMembers,
-                some2DArray: some2DArray,
-                someTuple: someTuple,
-                someTupleWithDynamicTypes: someTupleWithDynamicTypes,
-                someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
-            };
-
-            const calldata = method.encode(args);
-            console.log(calldata);
-
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
-            console.log(method.getSignature());
-
-            const expectedCalldata = '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
-            //const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata, { structsAsObjects: true });
-            const decodedValueJson = JSON.stringify(decodedValue);
-            console.log(`DECODED`, '*'.repeat(200), '\n', decodedValueJson);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Crazy ABI #1', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
-
-            const args = [
-                new BigNumber(256745454),
-                new BigNumber(-256745454),
-                new BigNumber(434244),
-                '0x43',
-                '0x0001020304050607080911121314151617181920212223242526272829303132',
-                '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
-                'Little peter piper piped a piping pepper pot',
-                '0xe41d2489571d322189246dafa5ebde1f4699f498',
-                true
-            ];
-
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-
-        it('Types with default widths', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
-            console.log(method);
-            const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Array of Static Tuples (Array has defined length)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
-
-            let value = 0;
-            const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Array of Static Tuples (Array has dynamic length)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
-
-            let value = 0;
-            const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Array of Dynamic Tuples (Array has defined length)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
-
-            let value = 0;
-            const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
-
-            let value = 0;
-            const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Multidimensional Arrays / Static Members', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
-
-            // Eight 3-dimensional arrays of uint8[2][2][2]
-            let value = 0;
-            const args = [];
-            for (let i = 0; i < 8; ++i) {
-                args.push(
-                    [
-                        [
-                            [new BigNumber(++value), new BigNumber(++value)],
-                            [new BigNumber(++value), new BigNumber(++value)],
-                        ],
-                        [
-                            [new BigNumber(++value), new BigNumber(++value)],
-                            [new BigNumber(++value), new BigNumber(++value)],
-                        ]
-                    ]
-                );
-            }
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; expect(calldata).to.be.equal(expectedCalldata);
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Multidimensional Arrays / Dynamic Members', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
-
-            // Eight 3-dimensional arrays of string[2][2][2]
-            let value = 0;
-            const args = [];
-            for (let i = 0; i < 4; ++i) {
-                args.push(
-                    [
-                        [
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                        ],
-                        [
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                        ]
-                    ]
-                );
-            }
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Fixed Lenfgth Array / Dynamic Members', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
-            const args = [["Brave", "New", "World"]];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
-            const expectedCalldata =
-                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Fixed Lenfgth Array / Dynamic Members', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
-            const args = [["Brave", "New", "World"]];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
-            const expectedCalldata =
-                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Unfixed Length Array / Dynamic Members ABI', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
-            const args = [["Brave", "New", "World"]];
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Unfixed Length Array / Static Members ABI', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-            const calldata = method.encode(args);
-            const expectedCalldata = '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-
-        it('Fixed Length Array / Static Members ABI', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-            const calldata = method.encode(args);
-            const expectedCalldata =
-                '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-
-        it('Simple ABI 2', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.simpleAbi2);
-
-            const args = [
-                '0xaf', // e (bytes1)
-                '0x0001020304050607080911121314151617181920212223242526272829303132', // f (bytes32)
-                '0x616161616161616161616161616161616161616161616161616161616161616161616161616161611114f324567838475647382938475677448899338457668899002020202020', // g
-                'My first name is Greg and my last name is Hysen, what do ya know!', // h
-            ];
-
-            const calldata = method.encode(args);
-            const expectedCalldata =
-                '0x7ac2bd96af000000000000000000000000000000000000000000000000000000000000000001020304050607080911121314151617181920212223242526272829303132000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Array ABI', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
-            console.log(method);
-            const args = [['five', 'six', 'seven']];
-            const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Static Tuple', async () => {
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
-            const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
-            const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata = '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Dynamic Tuple (Array input)', async () => {
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const args = [[new BigNumber(5), 'five']];
-            const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-        it('Dynamic Tuple (Object input)', async () => {
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
-
-        it.skip('Nested Tuples', async () => {
-            // Couldn't get nested tuples to work with Remix
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.nestedTuples);
-            const firstTuple = {
-                someUint32: new BigNumber(30472),
-                nestedTuple: {
-                    someUint: new BigNumber('48384725243211555532'),
-                    someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
-                }
-            };
-            const secondTuple = {
-                someUint: new BigNumber(2984237422),
-                someStr: 'This string will exceed 256 bits, so it will spill into the next word of memory.',
-                nestedTuple: {
-                    someUint32: new BigNumber(23),
-                    secondNestedTuple: {
-                        someUint: new BigNumber(234324),
-                        someStr: 'Im also a short string -- oops I just got loooooooooooooooooonger!',
-                        someBytes: '0x23847287fff3472984723498ff23487324987aaa237438911873429472ba',
-                        someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
-                    }
-                },
-                someBytes: '0x2834y3947289423u489aaaff4783924739847489',
-                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699afaf',
-            };
-            const thirdTuple = {
-                'someUint': new BigNumber(37422),
-                'someStr': 'This into the next word of memory. string will exceed 256 bits, so it will spill.',
-                'nestedTuple': {
-                    someUint32: new BigNumber(23999222),
-                    'secondNestedTuple': {
-                        'someUint': new BigNumber(324),
-                        'someStr': 'Im also a short st',
-                        'someBytes': '0x723498ff2348732498723847287fff3472984aaa237438911873429472ba',
-                        'someAddress': '0x46dafa5ebde1f4699f498e41d2489571d3221892'
-                    }
-                },
-                'someBytes': '0x947289423u489aaaff472834y383924739847489',
-                'someAddress': '0x46dafa5ebde1f46e41d2489571d322189299afaf',
-            };
-            const fourthTuple = {
-                'someUint': new BigNumber(222283488822),
-                'someStr': 'exceed 256 bits, so it will spill into the. This string will next word of memory.',
-                'nestedTuple': {
-                    someUint32: new BigNumber(2300),
-                    'secondNestedTuple': {
-                        'someUint': new BigNumber(343224),
-                        'someStr': 'The alphabet backwards is arguably easier to say if thats the way you learned the first time.',
-                        'someBytes': '0x87324987aaa23743891187323847287fff3472984723498ff234429472ba',
-                        'someAddress': '0x71d322189246dafa5ebe41d24895de1f4699f498'
-                    }
-                },
-                'someBytes': '0x2783924739847488343947289423u489aaaff490',
-                'someAddress': '0xebde1d322189246dafa1f4699afafe41d2489575',
-            };
-            const args = [
-                [firstTuple],
-                [secondTuple, thirdTuple, fourthTuple]
-            ];
-
-            console.log('*'.repeat(250), method, '*'.repeat(250));
-
-
-            const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-            console.log(JSON.stringify(args));
-
-            console.log(calldata);
-            const expectedCalldata = '0x';
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
-
-        it.skip('Object ABI (Object input - Missing Key)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([{ someUint: new BigNumber(5) }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-
-            // @TODO: Figure out how to catch throw
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
-
-        it.skip('Object ABI (Object input - Too Many Keys)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five', unwantedKey: 14 }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-
-            // @TODO: Figure out how to catch throw
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
-    });
-    /*
-        describe('Array', () => {
-            it('sample', async () => {
-                const testDataItem = { name: 'testArray', type: 'int[2]' };
-                const dataType = new AbiEncoder.SolArray(testDataItem);
-                console.log(JSON.stringify(dataType, null, 4));
-                console.log('*'.repeat(60));
-                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-                console.log(JSON.stringify(dataType, null, 4));
-                const hexValue = dataType.getHexValue();
-                console.log('*'.repeat(60));
-                console.log(hexValue);
-            });
-    
-            it('sample undefined size', async () => {
-                const testDataItem = { name: 'testArray', type: 'int[]' };
-                const dataType = new AbiEncoder.SolArray(testDataItem);
-                console.log(JSON.stringify(dataType, null, 4));
-                console.log('*'.repeat(60));
-                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-                console.log(JSON.stringify(dataType, null, 4));
-                const hexValue = dataType.getHexValue();
-                console.log('*'.repeat(60));
-                console.log(hexValue);
-            });
-    
-            it('sample dynamic types', async () => {
-                const testDataItem = { name: 'testArray', type: 'string[]' };
-                const dataType = new AbiEncoder.SolArray(testDataItem);
-                console.log(JSON.stringify(dataType, null, 4));
-                console.log('*'.repeat(60));
-                dataType.assignValue(['five', 'six', 'seven']);
-                console.log(JSON.stringify(dataType, null, 4));
-                const hexValue = dataType.getHexValue();
-                console.log('*'.repeat(60));
-                console.log(hexValue);
-                const calldata = new AbiEncoder.Calldata('0x01020304', 1);
-                dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
-                console.log('*'.repeat(60));
-                console.log(calldata.getHexValue());
-            });
-        });
-    
-        describe('Address', () => {
-            const testAddressDataItem = { name: 'testAddress', type: 'address' };
-            it('Valid Address', async () => {
-                const addressDataType = new AbiEncoder.Address(testAddressDataItem);
-                addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
-                const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
-    
-                console.log(addressDataType.getHexValue());
-                console.log(expectedAbiEncodedAddress);
-                expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
-            });
-        });
-    
-        describe('Bool', () => {
-            const testBoolDataItem = { name: 'testBool', type: 'bool' };
-            it('True', async () => {
-                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-                boolDataType.assignValue(true);
-                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
-                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
-            });
-    
-            it('False', async () => {
-                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-                boolDataType.assignValue(false);
-                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
-                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
-            });
-        });
-    
-        describe('Integer', () => {
-            const testIntDataItem = { name: 'testInt', type: 'int' };
-            it('Positive - Base case', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(1));
-                const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            it('Positive', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(437829473));
-                const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            it('Negative - Base case', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(-1));
-                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            it('Negative', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(-437829473));
-                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            // TODO: Add bounds tests + tests for different widths
-        });
-    
-        describe('Unsigned Integer', () => {
-            const testIntDataItem = { name: 'testUInt', type: 'uint' };
-            it('Lower Bound', async () => {
-                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-                uintDataType.assignValue(new BigNumber(0));
-                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
-                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-            });
-    
-            it('Base Case', async () => {
-                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-                uintDataType.assignValue(new BigNumber(1));
-                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-            });
-    
-            it('Random value', async () => {
-                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-                uintDataType.assignValue(new BigNumber(437829473));
-                const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-            });
-    
-            // TODO: Add bounds tests + tests for different widths
-        });
-    
-        describe('Static Bytes', () => {
-            it('Byte (padded)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x05');
-                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it.skip('Byte (no padding)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-    
-                // @TODO: This does not catch the Error
-                expect(byteDataType.assignValue('0x5')).to.throw();
-            });
-    
-            it('Bytes1', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x05');
-                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it('Bytes32 (padded)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
-                const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it('Bytes32 (unpadded)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x1a18bf61');
-                const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it.skip('Bytes32 - Too long', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-    
-                // @TODO: This does not catch the Error
-                expect(
-                    byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
-                ).to.throw(
-                    `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
-                );
-            });
-        });
-    
-        describe('Bytes (Dynamic)', () => {
-            const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
-            it('Less than 32 bytes', async () => {
-                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-                bytesDataType.assignValue('0x010203');
-                const expectedAbiEncodedBytes =
-                    '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
-    
-                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
-            });
-    
-            it('Greater than 32 bytes', async () => {
-                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-                const testValue = '0x' + '61'.repeat(40);
-                bytesDataType.assignValue(testValue);
-                const expectedAbiEncodedBytes =
-                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
-            });
-    
-            // @TODO: Add test for throw on half-byte
-            // @TODO: Test with no 0x prefix
-            // @TODO: Test with Buffer as input
-        });
-    
-        describe('String', () => {
-            const testStringDataItem = { name: 'testString', type: 'string' };
-            it('Less than 32 bytes', async () => {
-                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-                stringDataType.assignValue('five');
-                const expectedAbiEncodedString =
-                    '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-    
-                console.log(stringDataType.getHexValue());
-                console.log(expectedAbiEncodedString);
-                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
-            });
-    
-            it('Greater than 32 bytes', async () => {
-                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-                const testValue = 'a'.repeat(40);
-                stringDataType.assignValue(testValue);
-                const expectedAbiEncodedString =
-                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
-            });
-        });*/
-});
diff --git a/packages/order-utils/test/abi_samples.ts b/packages/order-utils/test/abi_samples.ts
deleted file mode 100644
index 5e8268f1a..000000000
--- a/packages/order-utils/test/abi_samples.ts
+++ /dev/null
@@ -1,814 +0,0 @@
-import { MethodAbi } from 'ethereum-types';
-
-export const simpleAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'greg',
-            type: 'uint256',
-        },
-        {
-            name: 'gregStr',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const stringAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'greg',
-            type: 'string[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const optimizerAbi2 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'stringArray',
-            type: 'string[]',
-        },
-        {
-            name: 'string',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const optimizerAbi3 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'uint8Array',
-            type: 'uint8[]',
-        },
-        {
-            components: [
-                {
-                    name: 'uint',
-                    type: 'uint',
-                },
-            ],
-            name: 'uintTuple',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const optimizerAbi4 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'uint8Array',
-            type: 'uint8[4]',
-        },
-        {
-            components: [
-                {
-                    name: 'uint',
-                    type: 'uint',
-                },
-            ],
-            name: 'uintTuple',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const typesWithDefaultWidthsAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someUint',
-            type: 'uint',
-        },
-        {
-            name: 'someInt',
-            type: 'int',
-        },
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someUint',
-            type: 'uint[]',
-        },
-        {
-            name: 'someInt',
-            type: 'int[]',
-        },
-        {
-            name: 'someByte',
-            type: 'byte[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const multiDimensionalArraysStaticTypeAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'a',
-            type: 'uint8[][][]',
-        },
-        {
-            name: 'b',
-            type: 'uint8[][][2]',
-        },
-        {
-            name: 'c',
-            type: 'uint8[][2][]',
-        },
-        {
-            name: 'd',
-            type: 'uint8[2][][]',
-        },
-        {
-            name: 'e',
-            type: 'uint8[][2][2]',
-        },
-        {
-            name: 'f',
-            type: 'uint8[2][2][]',
-        },
-        {
-            name: 'g',
-            type: 'uint8[2][][2]',
-        },
-        {
-            name: 'h',
-            type: 'uint8[2][2][2]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const multiDimensionalArraysDynamicTypeAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'a',
-            type: 'string[][][]',
-        },
-        {
-            name: 'b',
-            type: 'string[][][2]',
-        },
-        {
-            name: 'c',
-            type: 'string[][2][]',
-        },
-        {
-            name: 'h',
-            type: 'string[2][2][2]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const dynamicTupleAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const arrayOfStaticTuplesWithDefinedLengthAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint2',
-                    type: 'uint256',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[8]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const arrayOfStaticTuplesWithDynamicLengthAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint2',
-                    type: 'uint256',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const arrayOfDynamicTuplesWithDefinedLengthAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[8]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const arrayOfDynamicTuplesWithUndefinedLengthAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const arrayOfDynamicTuplesAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const multidimensionalArrayOfDynamicTuplesAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[][2][]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const staticTupleAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint1',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint2',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint3',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someBool',
-                    type: 'bool',
-                },
-            ],
-            name: 'order',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const staticArrayAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[3]',
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const staticArrayDynamicMembersAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'string[3]',
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const dynamicArrayDynamicMembersAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'string[]',
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const dynamicArrayStaticMembersAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[]',
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const crazyAbi1 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someUInt256',
-            type: 'uint256',
-        },
-        {
-            name: 'someInt256',
-            type: 'int256',
-        },
-        {
-            name: 'someInt32',
-            type: 'int32',
-        },
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someBytes32',
-            type: 'bytes32',
-        },
-        {
-            name: 'someBytes',
-            type: 'bytes',
-        },
-        {
-            name: 'someString',
-            type: 'string',
-        },
-        {
-            name: 'someAddress',
-            type: 'address',
-        },
-        {
-            name: 'someBool',
-            type: 'bool',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const crazyAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[3]',
-        },
-        {
-            name: 'someStaticArrayWithDynamicMembers',
-            type: 'string[2]',
-        },
-        {
-            name: 'someDynamicArrayWithDynamicMembers',
-            type: 'bytes[]',
-        },
-        {
-            name: 'some2DArray',
-            type: 'string[][]',
-        },
-        {
-            name: 'someTuple',
-            type: 'tuple',
-            components: [
-                {
-                    name: 'someUint32',
-                    type: 'uint32',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-            ],
-        },
-        {
-            name: 'someTupleWithDynamicTypes',
-            type: 'tuple',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                /*{
-                    name: 'someStrArray',
-                    type: 'string[]',
-                },*/
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        },
-        {
-            name: 'someArrayOfTuplesWithDynamicTypes',
-            type: 'tuple[]',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                /*{
-                    name: 'someStrArray',
-                    type: 'string[]',
-                },*/
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const nestedTuples = {
-    constant: false,
-    inputs: [
-        {
-            name: 'firstTuple',
-            type: 'tuple[1]',
-            components: [
-                {
-                    name: 'someUint32',
-                    type: 'uint32',
-                },
-                {
-                    name: 'nestedTuple',
-                    type: 'tuple',
-                    components: [
-                        {
-                            name: 'someUint',
-                            type: 'uint256',
-                        },
-                        {
-                            name: 'someAddress',
-                            type: 'address',
-                        },
-                    ],
-                },
-            ],
-        },
-        {
-            name: 'secondTuple',
-            type: 'tuple[]',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                {
-                    name: 'nestedTuple',
-                    type: 'tuple',
-                    components: [
-                        {
-                            name: 'someUint32',
-                            type: 'uint32',
-                        },
-                        {
-                            name: 'secondNestedTuple',
-                            type: 'tuple',
-                            components: [
-                                {
-                                    name: 'someUint',
-                                    type: 'uint256',
-                                },
-                                {
-                                    name: 'someStr',
-                                    type: 'string',
-                                },
-                                {
-                                    name: 'someBytes',
-                                    type: 'bytes',
-                                },
-                                {
-                                    name: 'someAddress',
-                                    type: 'address',
-                                },
-                            ],
-                        },
-                    ],
-                },
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        }
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const simpleAbi2 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someBytes32',
-            type: 'bytes32',
-        },
-        {
-            name: 'someBytes',
-            type: 'bytes',
-        },
-        {
-            name: 'someString',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const fillOrderAbi = {
-    constant: false,
-    inputs: [
-        {
-            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: 'order',
-            type: 'tuple',
-        },
-        {
-            name: 'takerAssetFillAmount',
-            type: 'uint256',
-        },
-        {
-            name: 'salt',
-            type: 'uint256',
-        },
-        {
-            name: 'orderSignature',
-            type: 'bytes',
-        },
-        {
-            name: 'takerSignature',
-            type: 'bytes',
-        },
-    ],
-    name: 'fillOrder',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
new file mode 100644
index 000000000..32278e5c5
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -0,0 +1,520 @@
+import ethUtil = require('ethereumjs-util');
+import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
+var _ = require('lodash');
+
+export interface DecodingRules {
+    structsAsObjects: boolean;
+}
+
+export interface EncodingRules {
+    optimize?: boolean;
+    annotate?: boolean;
+}
+
+export abstract class CalldataBlock {
+    private name: string;
+    private signature: string;
+    private offsetInBytes: number;
+    private headerSizeInBytes: number;
+    private bodySizeInBytes: number;
+    private relocatable: boolean;
+    private parentName: string;
+
+    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
+        this.name = name;
+        this.signature = signature;
+        this.parentName = parentName;
+        this.offsetInBytes = 0;
+        this.headerSizeInBytes = headerSizeInBytes;
+        this.bodySizeInBytes = bodySizeInBytes;
+        this.relocatable = relocatable;
+    }
+
+    protected setHeaderSize(headerSizeInBytes: number) {
+        this.headerSizeInBytes = headerSizeInBytes;
+    }
+
+    protected setBodySize(bodySizeInBytes: number) {
+        this.bodySizeInBytes = bodySizeInBytes;
+    }
+
+    protected setName(name: string) {
+        this.name = name;
+    }
+
+    public getName(): string {
+        return this.name;
+    }
+
+    public getParentName(): string {
+        return this.parentName;
+    }
+
+    public getSignature(): string {
+        return this.signature;
+    }
+
+    public isRelocatable(): boolean {
+        return this.relocatable;
+    }
+
+    public getHeaderSizeInBytes(): number {
+        return this.headerSizeInBytes;
+    }
+
+    public getBodySizeInBytes(): number {
+        return this.bodySizeInBytes;
+    }
+
+    public getSizeInBytes(): number {
+        return this.headerSizeInBytes + this.bodySizeInBytes;
+    }
+
+    public getOffsetInBytes(): number {
+        return this.offsetInBytes;
+    }
+
+    public setOffset(offsetInBytes: number) {
+        this.offsetInBytes = offsetInBytes;
+    }
+
+    public computeHash(): Buffer {
+        const rawData = this.getRawData();
+        const hash = ethUtil.sha3(rawData);
+        return hash;
+    }
+
+    public abstract toBuffer(): Buffer;
+    public abstract getRawData(): Buffer;
+}
+
+export class PayloadCalldataBlock extends CalldataBlock {
+    private payload: Buffer;
+
+    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = payload.byteLength;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.payload = payload;
+    }
+
+    public toBuffer(): Buffer {
+        return this.payload;
+    }
+
+    public getRawData(): Buffer {
+        return this.payload;
+    }
+}
+
+export class DependentCalldataBlock extends CalldataBlock {
+    public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    public static RAW_DATA_START = new Buffer('<');
+    public static RAW_DATA_END = new Buffer('>');
+    private parent: CalldataBlock;
+    private dependency: CalldataBlock;
+    private aliasFor: CalldataBlock | undefined;
+
+    constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
+        this.parent = parent;
+        this.dependency = dependency;
+        this.aliasFor = undefined;
+    }
+
+    public toBuffer(): Buffer {
+        const destinationOffset = (this.aliasFor !== undefined) ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
+        const parentOffset = this.parent.getOffsetInBytes();
+        const parentHeaderSize = this.parent.getHeaderSizeInBytes();
+        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
+        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
+        const evmWordWidthInBytes = 32;
+        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
+        return pointerBufPadded;
+    }
+
+    public getDependency(): CalldataBlock {
+        return this.dependency;
+    }
+
+    public setAlias(block: CalldataBlock) {
+        this.aliasFor = block;
+        this.setName(`${this.getName()} (alias for ${block.getName()})`);
+    }
+
+    public getAlias(): CalldataBlock | undefined {
+        return this.aliasFor;
+    }
+
+    public getRawData(): Buffer {
+        const dependencyRawData = this.dependency.getRawData();
+        const rawDataComponents: Buffer[] = [];
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
+        rawDataComponents.push(dependencyRawData);
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+}
+
+export class MemberCalldataBlock extends CalldataBlock {
+    private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private header: Buffer | undefined;
+    private members: CalldataBlock[];
+    private contiguous: boolean;
+
+    constructor(name: string, signature: string, parentName: string, relocatable: boolean, contiguous: boolean) {
+        super(name, signature, parentName, 0, 0, relocatable);
+        this.members = [];
+        this.header = undefined;
+        this.contiguous = contiguous;
+    }
+
+    public getRawData(): Buffer {
+        const rawDataComponents: Buffer[] = [];
+        if (this.header !== undefined) {
+            rawDataComponents.push(this.header);
+        }
+        _.each(this.members, (member: CalldataBlock) => {
+            const memberBuffer = member.getRawData();
+            rawDataComponents.push(memberBuffer);
+        });
+
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+
+    public setMembers(members: CalldataBlock[]) {
+        let bodySizeInBytes = 0;
+        _.each(members, (member: CalldataBlock) => {
+            bodySizeInBytes += member.getSizeInBytes();
+        });
+        this.members = members;
+        this.setBodySize(0);
+    }
+
+    public isContiguous(): boolean {
+        return true;
+    }
+
+    public setHeader(header: Buffer) {
+        this.setHeaderSize(header.byteLength);
+        this.header = header;
+    }
+
+    public toBuffer(): Buffer {
+        if (this.header !== undefined) return this.header;
+        return new Buffer('');
+    }
+
+    public getMembers(): CalldataBlock[] {
+        return this.members;
+    }
+}
+
+class Queue<T> {
+    private store: T[] = [];
+    push(val: T) {
+        this.store.push(val);
+    }
+    pushFront(val: T) {
+        this.store.unshift(val);
+    }
+    pop(): T | undefined {
+        return this.store.shift();
+    }
+    popBack(): T | undefined {
+        if (this.store.length === 0) return undefined;
+        const backElement = this.store.splice(-1, 1)[0];
+        return backElement;
+    }
+    merge(q: Queue<T>) {
+        this.store = this.store.concat(q.store);
+    }
+    mergeFront(q: Queue<T>) {
+        this.store = q.store.concat(this.store);
+    }
+    getStore(): T[] {
+        return this.store;
+    }
+    peek(): T | undefined {
+        return this.store.length >= 0 ? this.store[0] : undefined;
+    }
+}
+
+export class Calldata {
+    private selector: string;
+    private rules: EncodingRules;
+    private sizeInBytes: number;
+    private root: MemberCalldataBlock | undefined;
+
+    constructor(rules: EncodingRules) {
+        this.selector = '';
+        this.rules = rules;
+        this.sizeInBytes = 0;
+        this.root = undefined;
+    }
+
+    private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> {
+        const blockQueue = new Queue<CalldataBlock>();
+        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof MemberCalldataBlock) {
+                blockQueue.mergeFront(this.createQueue(member));
+            } else {
+                blockQueue.pushFront(member);
+            }
+        });
+
+        // Children
+        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
+                let dependency = member.getDependency();
+                if (dependency instanceof MemberCalldataBlock) {
+                    blockQueue.merge(this.createQueue(dependency));
+                } else {
+                    blockQueue.push(dependency);
+                }
+            }
+        });
+
+        blockQueue.pushFront(memberBlock);
+        return blockQueue;
+    }
+
+    private generateAnnotatedHexString(): string {
+        let hexValue = `${this.selector}`;
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = this.createQueue(this.root);
+
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        const functionBlock = valueQueue.peek();
+        let functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
+        while ((block = valueQueue.pop()) !== undefined) {
+            // Set f
+
+            // Process each block 1 word at a time
+            const size = block.getSizeInBytes();
+            const name = block.getName();
+            const parentName = block.getParentName();
+
+            //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
+            //const parentOffset = name.lastIndexOf(parentName);
+            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');//.replace(`${parentName}[`, '[');
+            const signature = block.getSignature();
+
+            // Current offset
+            let offsetStr = '';
+
+            // If this block is empty then it's a newline
+            let value = '';
+            let nameStr = '';
+            let line = '';
+            if (size === 0) {
+                offsetStr = ' '.repeat(10);
+                value = ' '.repeat(74);
+                nameStr = `### ${prettyName.padEnd(80)}`;
+                line = `\n${offsetStr}${value}${nameStr}`;
+            } else {
+                offsetStr = `0x${offset.toString(16)}`.padEnd(10, ' ');
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(0, 32))).padEnd(74);
+                if (block instanceof MemberCalldataBlock) {
+                    nameStr = `### ${prettyName.padEnd(80)}`;
+                    line = `\n${offsetStr}${value}${nameStr}`;
+                } else {
+                    nameStr = `    ${prettyName.padEnd(80)}`;
+                    line = `${offsetStr}${value}${nameStr}`;
+                }
+            }
+
+            for (let j = 32; j < size; j += 32) {
+                offsetStr = `0x${(offset + j).toString(16)}`.padEnd(10, ' ');
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + 32))).padEnd(74);
+                nameStr = ' '.repeat(40);
+
+                line = `${line}\n${offsetStr}${value}${nameStr}`;
+            }
+
+            // Append to hex value
+            hexValue = `${hexValue}\n${line}`;
+            offset += size;
+        }
+
+        return hexValue;
+    }
+
+    private generateCondensedHexString(): string {
+        let selectorBuffer = ethUtil.toBuffer(this.selector);
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = this.createQueue(this.root);
+        const valueBufs: Buffer[] = [selectorBuffer];
+        let block: CalldataBlock | undefined;
+        while ((block = valueQueue.pop()) !== undefined) {
+            valueBufs.push(block.toBuffer());
+        }
+
+        const combinedBuffers = Buffer.concat(valueBufs);
+        const hexValue = ethUtil.bufferToHex(combinedBuffers);
+        return hexValue;
+    }
+
+    public optimize() {
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const blocksByHash: { [key: string]: CalldataBlock } = {};
+
+        // 1. Create a queue of subtrees by hash
+        // Note that they are ordered the same as 
+        const subtreeQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        while ((block = subtreeQueue.popBack()) !== undefined) {
+            if (block instanceof DependentCalldataBlock) {
+                const blockHashBuf = block.getDependency().computeHash();
+                const blockHash = ethUtil.bufferToHex(blockHashBuf);
+                if (blockHash in blocksByHash) {
+                    const blockWithSameHash = blocksByHash[blockHash];
+                    if (blockWithSameHash !== block.getDependency()) {
+                        block.setAlias(blockWithSameHash);
+                    }
+                }
+                continue;
+            }
+
+            const blockHashBuf = block.computeHash();
+            const blockHash = ethUtil.bufferToHex(blockHashBuf);
+            if (blockHash in blocksByHash === false) {
+                blocksByHash[blockHash] = block;
+            }
+        }
+    }
+
+    public toHexString(): string {
+        if (this.root === undefined) {
+            throw new Error('expected root');
+        }
+
+        if (this.rules.optimize) this.optimize();
+
+        const offsetQueue = this.createQueue(this.root);
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        while ((block = offsetQueue.pop()) !== undefined) {
+            block.setOffset(offset);
+            offset += block.getSizeInBytes();
+        }
+
+        const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
+        return hexValue;
+    }
+
+    public getSelectorHex(): string {
+        return this.selector;
+    }
+
+    public getSizeInBytes(): number {
+        return this.sizeInBytes;
+    }
+
+    public toAnnotatedString(): string {
+        return "";
+    }
+
+    public setRoot(block: MemberCalldataBlock) {
+        this.root = block;
+        this.sizeInBytes += block.getSizeInBytes();
+    }
+
+    public setSelector(selector: string) {
+        // Ensure we have a 0x prefix
+        if (selector.startsWith('0x')) {
+            this.selector = selector;
+        } else {
+            this.selector = `$0x${selector}`;
+        }
+
+        // The selector must be 10 characters: '0x' followed by 4 bytes (two hex chars per byte)
+        if (this.selector.length !== 10) {
+            throw new Error(`Invalid selector '${this.selector}'`);
+        }
+        this.sizeInBytes += 8;
+    }
+}
+
+export class RawCalldata {
+    private value: Buffer;
+    private offset: number; // tracks current offset into raw calldata; used for parsing
+    private selector: string;
+    private scopes: Queue<number>;
+
+    constructor(value: string | Buffer) {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Expected raw calldata to start with '0x'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
+        this.value = valueBuf.slice(4); // disregard selector
+        this.offset = 0;
+        this.scopes = new Queue<number>();
+        this.scopes.push(0);
+    }
+
+    public popBytes(lengthInBytes: number): Buffer {
+        const value = this.value.slice(this.offset, this.offset + lengthInBytes);
+        this.setOffset(this.offset + lengthInBytes);
+        return value;
+    }
+
+    public popWord(): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(wordInBytes);
+    }
+
+    public popWords(length: number): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(length * wordInBytes);
+    }
+
+    public readBytes(from: number, to: number): Buffer {
+        const value = this.value.slice(from, to);
+        return value;
+    }
+
+    public setOffset(offsetInBytes: number) {
+        this.offset = offsetInBytes;
+    }
+
+    public startScope() {
+        this.scopes.pushFront(this.offset);
+    }
+
+    public endScope() {
+        this.scopes.pop();
+    }
+
+    public getOffset(): number {
+        return this.offset;
+    }
+
+    public toAbsoluteOffset(relativeOffset: number) {
+        const scopeOffset = this.scopes.peek();
+        if (scopeOffset === undefined) {
+            throw new Error(`Tried to access undefined scope.`);
+        }
+        const absoluteOffset = relativeOffset + scopeOffset;
+        return absoluteOffset;
+    }
+
+    public getSelector(): string {
+        return this.selector;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
new file mode 100644
index 000000000..3b4028abd
--- /dev/null
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -0,0 +1,322 @@
+import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
+import { MethodAbi, DataItem } from 'ethereum-types';
+import { DecodingRules, EncodingRules } from './calldata';
+import { BigNumber } from '../configured_bignumber';
+import ethUtil = require('ethereumjs-util');
+var _ = require('lodash');
+
+export interface DataTypeFactory {
+    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
+    mapDataItemToDataType: (dataItem: DataItem) => DataType;
+}
+
+export abstract class DataType {
+    private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
+    private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
+
+    private dataItem: DataItem;
+    private factory: DataTypeFactory;
+
+    constructor(dataItem: DataItem, factory: DataTypeFactory) {
+        this.dataItem = dataItem;
+        this.factory = factory;
+    }
+
+    public getDataItem(): DataItem {
+        return this.dataItem;
+    }
+
+    public getFactory(): DataTypeFactory {
+        return this.factory;
+    }
+
+    public encode(value: any, rules?: EncodingRules, selector?: string): string {
+        const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
+        const calldata = new Calldata(rules_);
+        if (selector) calldata.setSelector(selector);
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
+        const calldataHex = calldata.toHexString();
+        return calldataHex;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules): any {
+        const rawCalldata = new RawCalldata(calldata);
+        const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
+        const value = this.generateValue(rawCalldata, rules_);
+        return value;
+    }
+
+    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
+    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
+    public abstract getSignature(): string;
+    public abstract isStatic(): boolean;
+}
+
+export abstract class PayloadDataType extends DataType {
+    protected hasConstantSize: boolean;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+        super(dataItem, factory);
+        this.hasConstantSize = hasConstantSize;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
+        const encodedValue = this.encodeValue(value);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const relocatable = false;
+        const block = new PayloadCalldataBlock(name, signature, parentName, /*offsetInBytes,*/ relocatable, encodedValue);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const value = this.decodeValue(calldata);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        // If a payload has a constant size then it's static
+        return this.hasConstantSize;
+    }
+
+    public abstract encodeValue(value: any): Buffer;
+    public abstract decodeValue(calldata: RawCalldata): any;
+}
+
+export abstract class DependentDataType extends DataType {
+    protected dependency: DataType;
+    protected parent: DataType;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+        super(dataItem, factory);
+        this.dependency = dependency;
+        this.parent = parent;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
+        if (parentBlock === undefined) {
+            throw new Error(`DependentDataType requires a parent block to generate its block`);
+        }
+        const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const relocatable = false;
+        const block = new DependentCalldataBlock(name, signature, parentName, relocatable, dependencyBlock, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const destinationOffsetBuf = calldata.popWord();
+        const currentOffset = calldata.getOffset();
+        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
+        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
+        calldata.setOffset(destinationOffsetAbsolute);
+        const value = this.dependency.generateValue(calldata, rules);
+        calldata.setOffset(currentOffset);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        return true;
+    }
+}
+
+export interface MemberMap {
+    [key: string]: number;
+}
+
+export abstract class MemberDataType extends DataType {
+    private memberMap: MemberMap;
+    private members: DataType[];
+    private isArray: boolean;
+    protected arrayLength: number | undefined;
+    protected arrayElementType: string | undefined;
+
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
+        super(dataItem, factory);
+        this.memberMap = {};
+        this.members = [];
+        this.isArray = isArray;
+        this.arrayLength = arrayLength;
+        this.arrayElementType = arrayElementType;
+        if (isArray && arrayLength !== undefined) {
+            [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
+        } else if (!isArray) {
+            [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
+        }
+    }
+
+    private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+        // Sanity check
+        if (dataItem.components === undefined) {
+            throw new Error(`Expected components`);
+        }
+
+        let members: DataType[] = [];
+        let memberMap: MemberMap = {};
+        _.each(dataItem.components, (memberItem: DataItem) => {
+            const childDataItem = {
+                type: memberItem.type,
+                name: `${dataItem.name}.${memberItem.name}`,
+            } as DataItem;
+            const components = memberItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[memberItem.name] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberMap];
+    }
+
+    private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        let members: DataType[] = [];
+        let memberMap: MemberMap = {};
+        const range = _.range(length);
+        _.each(range, (idx: number) => {
+            const childDataItem = {
+                type: this.arrayElementType,
+                name: `${dataItem.name}[${idx.toString(10)}]`,
+            } as DataItem;
+            const components = dataItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[idx.toString(10)] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberMap];
+    }
+
+    protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
+        // Sanity check length
+        if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
+            throw new Error(
+                `Expected array of ${JSON.stringify(
+                    this.arrayLength,
+                )} elements, but got array of length ${JSON.stringify(value.length)}`,
+            );
+        }
+
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
+
+        let members = this.members;
+        if (this.isArray && this.arrayLength === undefined) {
+            [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
+
+            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
+            methodBlock.setHeader(lenBuf);
+        }
+
+        const memberBlocks: CalldataBlock[] = [];
+        _.each(members, (member: DataType, idx: number) => {
+            const block = member.generateCalldataBlock(value[idx], methodBlock);
+            memberBlocks.push(block);
+        });
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
+    }
+
+    protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
+        const memberBlocks: CalldataBlock[] = [];
+        let childMap = _.cloneDeep(this.memberMap);
+        _.forOwn(obj, (value: any, key: string) => {
+            if (key in childMap === false) {
+                throw new Error(`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`);
+            }
+            const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
+            memberBlocks.push(block);
+            delete childMap[key];
+        });
+
+        if (Object.keys(childMap).length !== 0) {
+            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+        }
+
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
+    }
+
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value, parentBlock) : this.generateCalldataBlockFromObject(value, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
+        let members = this.members;
+        if (this.isArray && this.arrayLength === undefined) {
+            const arrayLengthBuf = calldata.popWord();
+            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+            const hexBase = 16;
+            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
+
+            [members,] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+        }
+
+        calldata.startScope();
+        let value: any[] | object;
+        if (rules.structsAsObjects && !this.isArray) {
+            value = {};
+            _.each(this.memberMap, (idx: number, key: string) => {
+                const member = this.members[idx];
+                let memberValue = member.generateValue(calldata, rules);
+                (value as { [key: string]: any })[key] = memberValue;
+            });
+        } else {
+            value = [];
+            _.each(members, (member: DataType, idx: number) => {
+                let memberValue = member.generateValue(calldata, rules);
+                (value as any[]).push(memberValue);
+            });
+        }
+        calldata.endScope();
+        return value;
+    }
+
+    protected computeSignatureOfMembers(): string {
+        // Compute signature of members
+        let signature = `(`;
+        _.each(this.members, (member: DataType, i: number) => {
+            signature += member.getSignature();
+            if (i < this.members.length - 1) {
+                signature += ',';
+            }
+        });
+        signature += ')';
+        return signature;
+    }
+
+    public isStatic(): boolean {
+        /* For Tuple:
+                    const isStaticTuple = this.children.length === 0;
+                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
+
+           For Array:
+                if isLengthDefined = false then this is false
+
+                Otherwise if the first element is a Pointer then false
+        */
+
+        if (this.isArray && this.arrayLength === undefined) {
+            return false;
+        }
+
+        // Search for dependent members
+        const dependentMember = _.find(this.members, (member: DataType) => {
+            return (member instanceof DependentDataType);
+        });
+        const isStatic = (dependentMember === undefined); // static if we couldn't find a dependent member
+        return isStatic;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
new file mode 100644
index 000000000..2973596fe
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -0,0 +1,550 @@
+import { DataType, DataTypeFactory, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+
+import { DecodingRules, EncodingRules } from './calldata';
+
+import { MethodAbi, DataItem } from 'ethereum-types';
+
+import ethUtil = require('ethereumjs-util');
+
+import { Calldata, RawCalldata } from './calldata';
+
+import { BigNumber } from '../configured_bignumber';
+
+var _ = require('lodash');
+
+export interface DataTypeStaticInterface {
+    matchGrammar: (type: string) => boolean;
+    encodeValue: (value: any) => Buffer;
+    decodeValue: (rawCalldata: RawCalldata) => any;
+}
+
+export class Address extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Address.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'address';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'address';
+    }
+
+    public encodeValue(value: boolean): Buffer {
+        const evmWordWidth = 32;
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(12);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+}
+
+export class Bool extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bool.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bool.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'bool';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bool';
+    }
+
+    public encodeValue(value: boolean): Buffer {
+        const evmWordWidth = 32;
+        const encodedValue = value === true ? '0x1' : '0x0';
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): boolean {
+        const valueBuf = calldata.popWord();
+        const valueHex = ethUtil.bufferToHex(valueBuf);
+        const valueNumber = new BigNumber(valueHex, 16);
+        let value: boolean = (valueNumber.equals(0)) ? false : true;
+        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
+            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
+        }
+        return value;
+    }
+}
+
+abstract class Number extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    static MAX_WIDTH: number = 256;
+    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
+    width: number = Number.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem, matcher: RegExp) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Number.SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = matcher.exec(dataItem.type);
+        if (matches === null) {
+            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
+        }
+        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
+            this.width = parseInt(matches[1]);
+        } else {
+            this.width = 256;
+        }
+    }
+
+    public encodeValue(value: BigNumber): Buffer {
+        if (value.greaterThan(this.getMaxValue())) {
+            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+        } else if (value.lessThan(this.getMinValue())) {
+            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+        }
+
+        const hexBase = 16;
+        const evmWordWidth = 32;
+        let valueBuf: Buffer;
+        if (value.greaterThanOrEqualTo(0)) {
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
+        } else {
+            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
+            // Step 1/3: Convert value to positive binary string
+            const binBase = 2;
+            const valueBin = value.times(-1).toString(binBase);
+
+            // Step 2/3: Invert binary value
+            const bitsInEvmWord = 256;
+            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
+            _.each(valueBin, (bit: string) => {
+                invertedValueBin += bit === '1' ? '0' : '1';
+            });
+            const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+            // Step 3/3: Add 1 to inverted value
+            // The result is the two's-complement represent of the input value.
+            const negativeValue = invertedValue.plus(1);
+
+            // Convert the negated value to a hex string
+            valueBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
+                evmWordWidth,
+            );
+        }
+
+        return valueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): BigNumber {
+        const paddedValueBuf = calldata.popWord();
+        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
+        let value = new BigNumber(paddedValueHex, 16);
+        if (this instanceof Int) {
+            // Check if we're negative
+            const binBase = 2;
+            const paddedValueBin = value.toString(binBase);
+            const valueBin = paddedValueBin.slice(paddedValueBin.length - this.width);
+            if (valueBin[0].startsWith('1')) {
+                // Negative
+                // Step 1/3: Invert binary value
+                let invertedValueBin = '';
+                _.each(valueBin, (bit: string) => {
+                    invertedValueBin += bit === '1' ? '0' : '1';
+                });
+                const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+                // Step 2/3: Add 1 to inverted value
+                // The result is the two's-complement represent of the input value.
+                const positiveValue = invertedValue.plus(1);
+
+                // Step 3/3: Invert positive value
+                const negativeValue = positiveValue.times(-1);
+                value = negativeValue;
+            }
+        }
+
+        return value;
+    }
+
+    public abstract getMaxValue(): BigNumber;
+    public abstract getMinValue(): BigNumber;
+}
+
+export class Int extends Number {
+    static matcher = RegExp(
+        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, Int.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width - 1).times(-1);
+    }
+
+    public getSignature(): string {
+        return `int${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class UInt extends Number {
+    static matcher = RegExp(
+        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, UInt.matcher);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this.width).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getSignature(): string {
+        return `uint${this.width}`;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Byte extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    static matcher = RegExp(
+        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+    );
+
+    static DEFAULT_WIDTH = 1;
+    width: number = Byte.DEFAULT_WIDTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Byte.SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = Byte.matcher.exec(dataItem.type);
+        if (!Byte.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
+        }
+        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
+            this.width = parseInt(matches[2]);
+        } else {
+            this.width = Byte.DEFAULT_WIDTH;
+        }
+    }
+
+    public getSignature(): string {
+        // Note that `byte` reduces to `bytes1`
+        return `bytes${this.width}`;
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        // Convert value into a buffer and do bounds checking
+        const valueBuf = ethUtil.toBuffer(value);
+        if (valueBuf.byteLength > this.width) {
+            throw new Error(
+                `Tried to assign ${value} (${
+                valueBuf.byteLength
+                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
+            );
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        // Store value as hex
+        const evmWordWidth = 32;
+        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
+        return paddedValue;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(0, this.width);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Bytes extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+    static UNDEFINED_LENGTH = new BigNumber(-1);
+    length: BigNumber = Bytes.UNDEFINED_LENGTH;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bytes.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
+        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
+        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, 16);
+        const wordsForValue = Math.ceil(length / 32);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const decodedValue = ethUtil.bufferToHex(valueBuf);
+        return decodedValue;
+    }
+
+    public getSignature(): string {
+        return 'bytes';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'bytes';
+    }
+}
+
+export class SolString extends PayloadDataType {
+    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), SolString.SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!SolString.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string): Buffer {
+        const wordsForValue = Math.ceil(value.length / 32);
+        const paddedBytesForValue = wordsForValue * 32;
+        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, 16);
+        const wordsForValue = Math.ceil(length / 32);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const value = valueBuf.toString('ascii');
+        return value;
+    }
+
+    public getSignature(): string {
+        return 'string';
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'string';
+    }
+}
+
+export class Pointer extends DependentDataType {
+
+    constructor(destDataType: DataType, parentDataType: DataType) {
+        const destDataItem = destDataType.getDataItem();
+        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
+        super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
+    }
+
+    public getSignature(): string {
+        return this.dependency.getSignature();
+    }
+}
+
+export class Tuple extends MemberDataType {
+    private tupleSignature: string;
+
+    constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+        if (!Tuple.matchGrammar(dataItem.type)) {
+            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
+        }
+        this.tupleSignature = this.computeSignatureOfMembers();
+    }
+
+    public getSignature(): string {
+        return this.tupleSignature;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'tuple';
+    }
+}
+
+export class SolArray extends MemberDataType {
+    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    private arraySignature: string;
+    private elementType: string;
+
+    constructor(dataItem: DataItem) {
+        // Sanity check
+        const matches = SolArray.matcher.exec(dataItem.type);
+        if (matches === null || matches.length !== 3) {
+            throw new Error(`Could not parse array: ${dataItem.type}`);
+        } else if (matches[1] === undefined) {
+            throw new Error(`Could not parse array type: ${dataItem.type}`);
+        } else if (matches[2] === undefined) {
+            throw new Error(`Could not parse array length: ${dataItem.type}`);
+        }
+
+        const isArray = true;
+        const arrayElementType = matches[1];
+        const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
+        super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
+        this.elementType = arrayElementType;
+        this.arraySignature = this.computeSignature();
+    }
+
+    private computeSignature(): string {
+        let dataItem = {
+            type: this.elementType,
+            name: 'N/A',
+        } as DataItem;
+        const components = this.getDataItem().components;
+        if (components !== undefined) {
+            dataItem.components = components;
+        }
+        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
+        const type = elementDataType.getSignature();
+        if (this.arrayLength === undefined) {
+            return `${type}[]`;
+        } else {
+            return `${type}[${this.arrayLength}]`;
+        }
+    }
+
+    public getSignature(): string {
+        return this.arraySignature;
+    }
+
+    public static matchGrammar(type: string): boolean {
+        return this.matcher.test(type);
+    }
+}
+
+export class Method extends MemberDataType {
+    private methodSignature: string;
+    private methodSelector: string;
+
+    // TMP
+    public selector: string;
+
+    constructor(abi: MethodAbi) {
+        super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
+        this.methodSignature = this.computeSignature();
+        this.selector = this.methodSelector = this.computeSelector();
+
+    }
+
+    private computeSignature(): string {
+        const memberSignature = this.computeSignatureOfMembers();
+        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
+        return methodSignature;
+    }
+
+    private computeSelector(): string {
+        const signature = this.computeSignature();
+        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(0, 4)));
+        return selector;
+    }
+
+    public encode(value: any, rules?: EncodingRules): string {
+        const calldata = super.encode(value, rules, this.selector);
+        return calldata;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules): any[] | object {
+        if (!calldata.startsWith(this.selector)) {
+            throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
+        }
+        const value = super.decode(calldata, rules);
+        return value;
+    }
+
+    public getSignature(): string {
+        return this.methodSignature;
+    }
+
+    public getSelector(): string {
+        return this.methodSelector;
+    }
+}
+
+export class EvmDataTypeFactory implements DataTypeFactory {
+    private static instance: DataTypeFactory;
+
+    private constructor() { }
+
+    public static getInstance(): DataTypeFactory {
+        if (!EvmDataTypeFactory.instance) {
+            EvmDataTypeFactory.instance = new EvmDataTypeFactory();
+        }
+        return EvmDataTypeFactory.instance;
+    }
+
+    public mapDataItemToDataType(dataItem: DataItem): DataType {
+        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
+        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
+        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
+        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
+        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
+        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
+        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
+        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
+        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
+        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
+        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
+
+        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+    }
+
+    public create(dataItem: DataItem, parentDataType: DataType): DataType {
+        const dataType = this.mapDataItemToDataType(dataItem);
+        if (dataType.isStatic()) {
+            return dataType;
+        }
+
+        const pointer = new Pointer(dataType, parentDataType);
+        return pointer;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts
new file mode 100644
index 000000000..991edb8c5
--- /dev/null
+++ b/packages/utils/src/abi_encoder/index.ts
@@ -0,0 +1,2 @@
+export { EncodingRules, DecodingRules } from './calldata';
+export * from './evm_data_types';
\ No newline at end of file
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index 0723e5788..c44530bbc 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -10,3 +10,4 @@ export { NULL_BYTES } from './constants';
 export { errorUtils } from './error_utils';
 export { fetchAsync } from './fetch_async';
 export { signTypedDataUtils } from './sign_typed_data_utils';
+export * from './abi_encoder';
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
new file mode 100644
index 000000000..2a8fba450
--- /dev/null
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -0,0 +1,935 @@
+import * as chai from 'chai';
+import 'mocha';
+
+// import { assert } from '@0x/order-utils/src/assert';
+
+import { chaiSetup } from './utils/chai_setup';
+import { BigNumber } from '../src/';
+//import * as AbiEncoder from './abi_encoder';
+
+import * as AbiEncoder from '../src/abi_encoder';
+import * as AbiSamples from './abi_samples';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe.only('ABI Encoder', () => {
+    describe.only('Optimizer', () => {
+
+    });
+
+    describe.only('ABI Tests at Method Level', () => {
+
+        it('Should reuse duplicated strings in string array', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
+            const strings = [
+                "Test String",
+                "Test String 2",
+                "Test String",
+                "Test String 2",
+            ];
+            const args = [strings];
+
+            // Verify optimized calldata is expected
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
+            //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+
+            // Verify args decode properly
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
+        });
+
+        it('Should point array elements to a duplicated value from another parameter', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
+            const stringArray = [
+                "Test String",
+                "Test String",
+                "Test String",
+                "Test String 2",
+            ];
+            const string = 'Test String';
+            const args = [stringArray, string];
+
+            // Verify optimized calldata is expected
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata = '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+
+            // Verify args decode properly
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
+        });
+
+
+        it('Optimizer #3 (tuple should point to array)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi3);
+            const uint8Array = [
+                new BigNumber(100),
+                new BigNumber(150),
+                new BigNumber(200),
+                new BigNumber(225),
+            ];
+            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
+            const args = [uint8Array, uintTupleArray];
+
+
+            const TEST = method.encode(args, { optimize: true, annotate: true });
+            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
+
+            const optimizedCalldata = method.encode(args, { optimize: true });
+
+            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            console.log(JSON.stringify(decodedArgs));
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+
+        it('Optimizer #4 (Expect no optimization)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
+            const uint8Array = [
+                new BigNumber(100),
+                new BigNumber(150),
+                new BigNumber(200),
+                new BigNumber(225),
+            ];
+            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
+            const args = [uint8Array, uintTupleArray];
+
+
+            const TEST = method.encode(args, { optimize: true, annotate: true });
+            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
+
+            const optimizedCalldata = method.encode(args, { optimize: true });
+
+            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            console.log(JSON.stringify(decodedArgs));
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+
+        it('Crazy ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
+            console.log(method.getSignature());
+
+            const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
+            const someStaticArrayWithDynamicMembers = [
+                'the little piping piper piped a piping pipper papper',
+                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+            ];
+            const someDynamicArrayWithDynamicMembers = [
+                '0x38745637834987324827439287423897238947239847',
+                '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
+                '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
+            ];
+            const some2DArray = [
+                [
+                    'some string',
+                    'some another string',
+                    'there are just too many stringsup in',
+                    'here',
+                    'yall ghonna make me lose my mind',
+                ],
+                [
+                    'the little piping piper piped a piping pipper papper',
+                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+                ],
+                [],
+            ];
+            const someTuple = {
+                someUint32: new BigNumber(4037824789),
+                someStr: 'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.'
+            };
+            const someTupleWithDynamicTypes = {
+                someUint: new BigNumber(4024789),
+                someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+                someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
+                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
+            };
+            const someTupleWithDynamicTypes2 = {
+                someUint: new BigNumber(9024789),
+                someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
+                someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
+                someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
+            };
+            const someTupleWithDynamicTypes3 = {
+                someUint: new BigNumber(1024789),
+                someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
+                someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
+                someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
+            };
+            const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
+
+            const args = {
+                someStaticArray: someStaticArray,
+                someStaticArrayWithDynamicMembers: someStaticArrayWithDynamicMembers,
+                someDynamicArrayWithDynamicMembers: someDynamicArrayWithDynamicMembers,
+                some2DArray: some2DArray,
+                someTuple: someTuple,
+                someTupleWithDynamicTypes: someTupleWithDynamicTypes,
+                someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
+            };
+
+            const calldata = method.encode(args);
+            console.log(calldata);
+
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            console.log(method.getSignature());
+
+            const expectedCalldata = '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
+            //const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata, { structsAsObjects: true });
+            const decodedValueJson = JSON.stringify(decodedValue);
+            console.log(`DECODED`, '*'.repeat(200), '\n', decodedValueJson);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Crazy ABI #1', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
+
+            const args = [
+                new BigNumber(256745454),
+                new BigNumber(-256745454),
+                new BigNumber(434244),
+                '0x43',
+                '0x0001020304050607080911121314151617181920212223242526272829303132',
+                '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
+                'Little peter piper piped a piping pepper pot',
+                '0xe41d2489571d322189246dafa5ebde1f4699f498',
+                true
+            ];
+
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+
+        it('Types with default widths', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
+            console.log(method);
+            const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Array of Static Tuples (Array has defined length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Array of Static Tuples (Array has dynamic length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Array of Dynamic Tuples (Array has defined length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
+
+            let value = 0;
+            const arrayOfTuples = [];
+            for (let i = 0; i < 8; ++i) {
+                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
+            }
+            const args = [arrayOfTuples];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Multidimensional Arrays / Static Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
+
+            // Eight 3-dimensional arrays of uint8[2][2][2]
+            let value = 0;
+            const args = [];
+            for (let i = 0; i < 8; ++i) {
+                args.push(
+                    [
+                        [
+                            [new BigNumber(++value), new BigNumber(++value)],
+                            [new BigNumber(++value), new BigNumber(++value)],
+                        ],
+                        [
+                            [new BigNumber(++value), new BigNumber(++value)],
+                            [new BigNumber(++value), new BigNumber(++value)],
+                        ]
+                    ]
+                );
+            }
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; expect(calldata).to.be.equal(expectedCalldata);
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Multidimensional Arrays / Dynamic Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
+
+            // Eight 3-dimensional arrays of string[2][2][2]
+            let value = 0;
+            const args = [];
+            for (let i = 0; i < 4; ++i) {
+                args.push(
+                    [
+                        [
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                        ],
+                        [
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                        ]
+                    ]
+                );
+            }
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(method.getSignature());
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Fixed Lenfgth Array / Dynamic Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
+            const args = [["Brave", "New", "World"]];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            const expectedCalldata =
+                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Fixed Lenfgth Array / Dynamic Members', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
+            const args = [["Brave", "New", "World"]];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            const expectedCalldata =
+                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Unfixed Length Array / Dynamic Members ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
+            const args = [["Brave", "New", "World"]];
+            const calldata = method.encode(args);
+            console.log(calldata);
+            console.log('*'.repeat(40));
+            console.log(JSON.stringify(args));
+            const expectedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Unfixed Length Array / Static Members ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+            const calldata = method.encode(args);
+            const expectedCalldata = '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+
+        it('Fixed Length Array / Static Members ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
+            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+            const calldata = method.encode(args);
+            const expectedCalldata =
+                '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+
+        it('Simple ABI 2', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.simpleAbi2);
+
+            const args = [
+                '0xaf', // e (bytes1)
+                '0x0001020304050607080911121314151617181920212223242526272829303132', // f (bytes32)
+                '0x616161616161616161616161616161616161616161616161616161616161616161616161616161611114f324567838475647382938475677448899338457668899002020202020', // g
+                'My first name is Greg and my last name is Hysen, what do ya know!', // h
+            ];
+
+            const calldata = method.encode(args);
+            const expectedCalldata =
+                '0x7ac2bd96af000000000000000000000000000000000000000000000000000000000000000001020304050607080911121314151617181920212223242526272829303132000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Array ABI', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
+            console.log(method);
+            const args = [['five', 'six', 'seven']];
+            const calldata = method.encode(args);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Static Tuple', async () => {
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
+            const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
+            const calldata = method.encode(args);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata = '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Dynamic Tuple (Array input)', async () => {
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
+            const args = [[new BigNumber(5), 'five']];
+            const calldata = method.encode(args);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+
+            // Test decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+
+        it('Dynamic Tuple (Object input)', async () => {
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
+            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.skip('Nested Tuples', async () => {
+            // Couldn't get nested tuples to work with Remix
+            // This is dynamic because it has dynamic members
+            const method = new AbiEncoder.Method(AbiSamples.nestedTuples);
+            const firstTuple = {
+                someUint32: new BigNumber(30472),
+                nestedTuple: {
+                    someUint: new BigNumber('48384725243211555532'),
+                    someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
+                }
+            };
+            const secondTuple = {
+                someUint: new BigNumber(2984237422),
+                someStr: 'This string will exceed 256 bits, so it will spill into the next word of memory.',
+                nestedTuple: {
+                    someUint32: new BigNumber(23),
+                    secondNestedTuple: {
+                        someUint: new BigNumber(234324),
+                        someStr: 'Im also a short string -- oops I just got loooooooooooooooooonger!',
+                        someBytes: '0x23847287fff3472984723498ff23487324987aaa237438911873429472ba',
+                        someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
+                    }
+                },
+                someBytes: '0x2834y3947289423u489aaaff4783924739847489',
+                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699afaf',
+            };
+            const thirdTuple = {
+                'someUint': new BigNumber(37422),
+                'someStr': 'This into the next word of memory. string will exceed 256 bits, so it will spill.',
+                'nestedTuple': {
+                    someUint32: new BigNumber(23999222),
+                    'secondNestedTuple': {
+                        'someUint': new BigNumber(324),
+                        'someStr': 'Im also a short st',
+                        'someBytes': '0x723498ff2348732498723847287fff3472984aaa237438911873429472ba',
+                        'someAddress': '0x46dafa5ebde1f4699f498e41d2489571d3221892'
+                    }
+                },
+                'someBytes': '0x947289423u489aaaff472834y383924739847489',
+                'someAddress': '0x46dafa5ebde1f46e41d2489571d322189299afaf',
+            };
+            const fourthTuple = {
+                'someUint': new BigNumber(222283488822),
+                'someStr': 'exceed 256 bits, so it will spill into the. This string will next word of memory.',
+                'nestedTuple': {
+                    someUint32: new BigNumber(2300),
+                    'secondNestedTuple': {
+                        'someUint': new BigNumber(343224),
+                        'someStr': 'The alphabet backwards is arguably easier to say if thats the way you learned the first time.',
+                        'someBytes': '0x87324987aaa23743891187323847287fff3472984723498ff234429472ba',
+                        'someAddress': '0x71d322189246dafa5ebe41d24895de1f4699f498'
+                    }
+                },
+                'someBytes': '0x2783924739847488343947289423u489aaaff490',
+                'someAddress': '0xebde1d322189246dafa1f4699afafe41d2489575',
+            };
+            const args = [
+                [firstTuple],
+                [secondTuple, thirdTuple, fourthTuple]
+            ];
+
+            console.log('*'.repeat(250), method, '*'.repeat(250));
+
+
+            const calldata = method.encode(args);
+            console.log(method.getSignature());
+            console.log(method.selector);
+            console.log(JSON.stringify(args));
+
+            console.log(calldata);
+            const expectedCalldata = '0x';
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.skip('Object ABI (Object input - Missing Key)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
+            const calldata = method.encode([{ someUint: new BigNumber(5) }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+
+            // @TODO: Figure out how to catch throw
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+
+        it.skip('Object ABI (Object input - Too Many Keys)', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
+            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five', unwantedKey: 14 }]);
+            console.log(method.getSignature());
+            console.log(method.selector);
+
+            console.log(calldata);
+            const expectedCalldata =
+                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+
+            // @TODO: Figure out how to catch throw
+            expect(calldata).to.be.equal(expectedCalldata);
+        });
+    });
+    /*
+        describe('Array', () => {
+            it('sample', async () => {
+                const testDataItem = { name: 'testArray', type: 'int[2]' };
+                const dataType = new AbiEncoder.SolArray(testDataItem);
+                console.log(JSON.stringify(dataType, null, 4));
+                console.log('*'.repeat(60));
+                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+                console.log(JSON.stringify(dataType, null, 4));
+                const hexValue = dataType.getHexValue();
+                console.log('*'.repeat(60));
+                console.log(hexValue);
+            });
+    
+            it('sample undefined size', async () => {
+                const testDataItem = { name: 'testArray', type: 'int[]' };
+                const dataType = new AbiEncoder.SolArray(testDataItem);
+                console.log(JSON.stringify(dataType, null, 4));
+                console.log('*'.repeat(60));
+                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+                console.log(JSON.stringify(dataType, null, 4));
+                const hexValue = dataType.getHexValue();
+                console.log('*'.repeat(60));
+                console.log(hexValue);
+            });
+    
+            it('sample dynamic types', async () => {
+                const testDataItem = { name: 'testArray', type: 'string[]' };
+                const dataType = new AbiEncoder.SolArray(testDataItem);
+                console.log(JSON.stringify(dataType, null, 4));
+                console.log('*'.repeat(60));
+                dataType.assignValue(['five', 'six', 'seven']);
+                console.log(JSON.stringify(dataType, null, 4));
+                const hexValue = dataType.getHexValue();
+                console.log('*'.repeat(60));
+                console.log(hexValue);
+                const calldata = new AbiEncoder.Calldata('0x01020304', 1);
+                dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
+                console.log('*'.repeat(60));
+                console.log(calldata.getHexValue());
+            });
+        });
+    
+        describe('Address', () => {
+            const testAddressDataItem = { name: 'testAddress', type: 'address' };
+            it('Valid Address', async () => {
+                const addressDataType = new AbiEncoder.Address(testAddressDataItem);
+                addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
+                const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+    
+                console.log(addressDataType.getHexValue());
+                console.log(expectedAbiEncodedAddress);
+                expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
+            });
+        });
+    
+        describe('Bool', () => {
+            const testBoolDataItem = { name: 'testBool', type: 'bool' };
+            it('True', async () => {
+                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+                boolDataType.assignValue(true);
+                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
+                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+            });
+    
+            it('False', async () => {
+                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+                boolDataType.assignValue(false);
+                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
+                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+            });
+        });
+    
+        describe('Integer', () => {
+            const testIntDataItem = { name: 'testInt', type: 'int' };
+            it('Positive - Base case', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(1));
+                const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            it('Positive', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(437829473));
+                const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            it('Negative - Base case', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(-1));
+                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            it('Negative', async () => {
+                const intDataType = new AbiEncoder.Int(testIntDataItem);
+                intDataType.assignValue(new BigNumber(-437829473));
+                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
+                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+            });
+    
+            // TODO: Add bounds tests + tests for different widths
+        });
+    
+        describe('Unsigned Integer', () => {
+            const testIntDataItem = { name: 'testUInt', type: 'uint' };
+            it('Lower Bound', async () => {
+                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+                uintDataType.assignValue(new BigNumber(0));
+                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
+                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+            });
+    
+            it('Base Case', async () => {
+                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+                uintDataType.assignValue(new BigNumber(1));
+                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+            });
+    
+            it('Random value', async () => {
+                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+                uintDataType.assignValue(new BigNumber(437829473));
+                const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+            });
+    
+            // TODO: Add bounds tests + tests for different widths
+        });
+    
+        describe('Static Bytes', () => {
+            it('Byte (padded)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x05');
+                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it.skip('Byte (no padding)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+    
+                // @TODO: This does not catch the Error
+                expect(byteDataType.assignValue('0x5')).to.throw();
+            });
+    
+            it('Bytes1', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x05');
+                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it('Bytes32 (padded)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
+                const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it('Bytes32 (unpadded)', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+                byteDataType.assignValue('0x1a18bf61');
+                const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+            });
+    
+            it.skip('Bytes32 - Too long', async () => {
+                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+    
+                // @TODO: This does not catch the Error
+                expect(
+                    byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
+                ).to.throw(
+                    `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
+                );
+            });
+        });
+    
+        describe('Bytes (Dynamic)', () => {
+            const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
+            it('Less than 32 bytes', async () => {
+                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+                bytesDataType.assignValue('0x010203');
+                const expectedAbiEncodedBytes =
+                    '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
+    
+                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+            });
+    
+            it('Greater than 32 bytes', async () => {
+                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+                const testValue = '0x' + '61'.repeat(40);
+                bytesDataType.assignValue(testValue);
+                const expectedAbiEncodedBytes =
+                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+            });
+    
+            // @TODO: Add test for throw on half-byte
+            // @TODO: Test with no 0x prefix
+            // @TODO: Test with Buffer as input
+        });
+    
+        describe('String', () => {
+            const testStringDataItem = { name: 'testString', type: 'string' };
+            it('Less than 32 bytes', async () => {
+                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+                stringDataType.assignValue('five');
+                const expectedAbiEncodedString =
+                    '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+    
+                console.log(stringDataType.getHexValue());
+                console.log(expectedAbiEncodedString);
+                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+            });
+    
+            it('Greater than 32 bytes', async () => {
+                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+                const testValue = 'a'.repeat(40);
+                stringDataType.assignValue(testValue);
+                const expectedAbiEncodedString =
+                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+            });
+        });*/
+});
diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts
new file mode 100644
index 000000000..5e8268f1a
--- /dev/null
+++ b/packages/utils/test/abi_samples.ts
@@ -0,0 +1,814 @@
+import { MethodAbi } from 'ethereum-types';
+
+export const simpleAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'uint256',
+        },
+        {
+            name: 'gregStr',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const stringAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const optimizerAbi2 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'stringArray',
+            type: 'string[]',
+        },
+        {
+            name: 'string',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const optimizerAbi3 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'uint8Array',
+            type: 'uint8[]',
+        },
+        {
+            components: [
+                {
+                    name: 'uint',
+                    type: 'uint',
+                },
+            ],
+            name: 'uintTuple',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const optimizerAbi4 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'uint8Array',
+            type: 'uint8[4]',
+        },
+        {
+            components: [
+                {
+                    name: 'uint',
+                    type: 'uint',
+                },
+            ],
+            name: 'uintTuple',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const typesWithDefaultWidthsAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someUint',
+            type: 'uint',
+        },
+        {
+            name: 'someInt',
+            type: 'int',
+        },
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someUint',
+            type: 'uint[]',
+        },
+        {
+            name: 'someInt',
+            type: 'int[]',
+        },
+        {
+            name: 'someByte',
+            type: 'byte[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multiDimensionalArraysStaticTypeAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'a',
+            type: 'uint8[][][]',
+        },
+        {
+            name: 'b',
+            type: 'uint8[][][2]',
+        },
+        {
+            name: 'c',
+            type: 'uint8[][2][]',
+        },
+        {
+            name: 'd',
+            type: 'uint8[2][][]',
+        },
+        {
+            name: 'e',
+            type: 'uint8[][2][2]',
+        },
+        {
+            name: 'f',
+            type: 'uint8[2][2][]',
+        },
+        {
+            name: 'g',
+            type: 'uint8[2][][2]',
+        },
+        {
+            name: 'h',
+            type: 'uint8[2][2][2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multiDimensionalArraysDynamicTypeAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'a',
+            type: 'string[][][]',
+        },
+        {
+            name: 'b',
+            type: 'string[][][2]',
+        },
+        {
+            name: 'c',
+            type: 'string[][2][]',
+        },
+        {
+            name: 'h',
+            type: 'string[2][2][2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const dynamicTupleAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfStaticTuplesWithDefinedLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[8]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfStaticTuplesWithDynamicLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfDynamicTuplesWithDefinedLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[8]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfDynamicTuplesWithUndefinedLengthAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayOfDynamicTuplesAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multidimensionalArrayOfDynamicTuplesAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[][2][]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const staticTupleAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint1',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint3',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someBool',
+                    type: 'bool',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const staticArrayAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const staticArrayDynamicMembersAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'string[3]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const dynamicArrayDynamicMembersAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'string[]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const dynamicArrayStaticMembersAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[]',
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const crazyAbi1 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someUInt256',
+            type: 'uint256',
+        },
+        {
+            name: 'someInt256',
+            type: 'int256',
+        },
+        {
+            name: 'someInt32',
+            type: 'int32',
+        },
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+        {
+            name: 'someAddress',
+            type: 'address',
+        },
+        {
+            name: 'someBool',
+            type: 'bool',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const crazyAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        },
+        {
+            name: 'someStaticArrayWithDynamicMembers',
+            type: 'string[2]',
+        },
+        {
+            name: 'someDynamicArrayWithDynamicMembers',
+            type: 'bytes[]',
+        },
+        {
+            name: 'some2DArray',
+            type: 'string[][]',
+        },
+        {
+            name: 'someTuple',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+        },
+        {
+            name: 'someTupleWithDynamicTypes',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                /*{
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },*/
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        },
+        {
+            name: 'someArrayOfTuplesWithDynamicTypes',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                /*{
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },*/
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const nestedTuples = {
+    constant: false,
+    inputs: [
+        {
+            name: 'firstTuple',
+            type: 'tuple[1]',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'nestedTuple',
+                    type: 'tuple',
+                    components: [
+                        {
+                            name: 'someUint',
+                            type: 'uint256',
+                        },
+                        {
+                            name: 'someAddress',
+                            type: 'address',
+                        },
+                    ],
+                },
+            ],
+        },
+        {
+            name: 'secondTuple',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                {
+                    name: 'nestedTuple',
+                    type: 'tuple',
+                    components: [
+                        {
+                            name: 'someUint32',
+                            type: 'uint32',
+                        },
+                        {
+                            name: 'secondNestedTuple',
+                            type: 'tuple',
+                            components: [
+                                {
+                                    name: 'someUint',
+                                    type: 'uint256',
+                                },
+                                {
+                                    name: 'someStr',
+                                    type: 'string',
+                                },
+                                {
+                                    name: 'someBytes',
+                                    type: 'bytes',
+                                },
+                                {
+                                    name: 'someAddress',
+                                    type: 'address',
+                                },
+                            ],
+                        },
+                    ],
+                },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const simpleAbi2 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const fillOrderAbi = {
+    constant: false,
+    inputs: [
+        {
+            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: 'order',
+            type: 'tuple',
+        },
+        {
+            name: 'takerAssetFillAmount',
+            type: 'uint256',
+        },
+        {
+            name: 'salt',
+            type: 'uint256',
+        },
+        {
+            name: 'orderSignature',
+            type: 'bytes',
+        },
+        {
+            name: 'takerSignature',
+            type: 'bytes',
+        },
+    ],
+    name: 'fillOrder',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
diff --git a/packages/utils/test/utils/chai_setup.ts b/packages/utils/test/utils/chai_setup.ts
new file mode 100644
index 000000000..1a8733093
--- /dev/null
+++ b/packages/utils/test/utils/chai_setup.ts
@@ -0,0 +1,13 @@
+import * as chai from 'chai';
+import chaiAsPromised = require('chai-as-promised');
+import ChaiBigNumber = require('chai-bignumber');
+import * as dirtyChai from 'dirty-chai';
+
+export const chaiSetup = {
+    configure(): void {
+        chai.config.includeStack = true;
+        chai.use(ChaiBigNumber());
+        chai.use(dirtyChai);
+        chai.use(chaiAsPromised);
+    },
+};
-- 
cgit v1.2.3


From 1f9ea7ed1b3d56a13b5e518adeed907eb830c02a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 15:34:27 -0800
Subject: Removed unnecessary imports from abi encoder tets

---
 packages/utils/src/index.ts             | 3 +--
 packages/utils/test/abi_encoder_test.ts | 4 ----
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index c44530bbc..2edc6a331 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -9,5 +9,4 @@ export { abiUtils } from './abi_utils';
 export { NULL_BYTES } from './constants';
 export { errorUtils } from './error_utils';
 export { fetchAsync } from './fetch_async';
-export { signTypedDataUtils } from './sign_typed_data_utils';
-export * from './abi_encoder';
+export { signTypedDataUtils } from './sign_typed_data_utils';
\ No newline at end of file
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 2a8fba450..0961458da 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -1,12 +1,8 @@
 import * as chai from 'chai';
 import 'mocha';
 
-// import { assert } from '@0x/order-utils/src/assert';
-
 import { chaiSetup } from './utils/chai_setup';
 import { BigNumber } from '../src/';
-//import * as AbiEncoder from './abi_encoder';
-
 import * as AbiEncoder from '../src/abi_encoder';
 import * as AbiSamples from './abi_samples';
 
-- 
cgit v1.2.3


From ebd4dbc6c6ebdf776ba1582367d3eda32717ba65 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 14 Nov 2018 15:55:10 -0800
Subject: Exports AbiEncoder as 1 unit

---
 packages/utils/src/index.ts             | 4 +++-
 packages/utils/test/abi_encoder_test.ts | 5 ++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index 2edc6a331..f59cbec8c 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -9,4 +9,6 @@ export { abiUtils } from './abi_utils';
 export { NULL_BYTES } from './constants';
 export { errorUtils } from './error_utils';
 export { fetchAsync } from './fetch_async';
-export { signTypedDataUtils } from './sign_typed_data_utils';
\ No newline at end of file
+export { signTypedDataUtils } from './sign_typed_data_utils';
+import * as AbiEncoder from './abi_encoder';
+export { AbiEncoder };
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 0961458da..8d78b61b5 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -2,8 +2,7 @@ import * as chai from 'chai';
 import 'mocha';
 
 import { chaiSetup } from './utils/chai_setup';
-import { BigNumber } from '../src/';
-import * as AbiEncoder from '../src/abi_encoder';
+import { BigNumber, AbiEncoder } from '../src/';
 import * as AbiSamples from './abi_samples';
 
 chaiSetup.configure();
@@ -29,7 +28,7 @@ describe.only('ABI Encoder', () => {
             // Verify optimized calldata is expected
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
-            //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
 
             // Verify args decode properly
             const decodedArgs = method.decode(optimizedCalldata);
-- 
cgit v1.2.3


From 8a8b904a292063d1adb3df0a84023610a3985f7f Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Thu, 15 Nov 2018 14:33:40 -0800
Subject: Use new ABI Encoder for contracts

---
 packages/utils/src/abi_encoder/calldata.ts       | 12 ++++++---
 packages/utils/src/abi_encoder/data_type.ts      |  2 +-
 packages/utils/src/abi_encoder/evm_data_types.ts | 32 +++++++++++++++++++---
 packages/utils/test/abi_encoder_test.ts          | 29 ++++++++++++++++++++
 packages/utils/test/abi_samples.ts               | 34 ++++++++++++++++++++++++
 5 files changed, 102 insertions(+), 7 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 32278e5c5..078767c22 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -456,13 +456,19 @@ export class RawCalldata {
     private selector: string;
     private scopes: Queue<number>;
 
-    constructor(value: string | Buffer) {
+    constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) {
         if (typeof value === 'string' && !value.startsWith('0x')) {
             throw new Error(`Expected raw calldata to start with '0x'`);
         }
         const valueBuf = ethUtil.toBuffer(value);
-        this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
-        this.value = valueBuf.slice(4); // disregard selector
+        if (hasSelectorPrefix) {
+            this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
+            this.value = valueBuf.slice(4); // disregard selector
+        } else {
+            this.selector = '0x';
+            this.value = valueBuf;
+        }
+
         this.offset = 0;
         this.scopes = new Queue<number>();
         this.scopes.push(0);
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 3b4028abd..f5a8087ea 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -6,7 +6,7 @@ import ethUtil = require('ethereumjs-util');
 var _ = require('lodash');
 
 export interface DataTypeFactory {
-    create: (dataItem: DataItem, parentDataType: DataType) => DataType;
+    create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
     mapDataItemToDataType: (dataItem: DataItem) => DataType;
 }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 2973596fe..d024a9bfa 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -106,7 +106,8 @@ abstract class Number extends PayloadDataType {
         }
     }
 
-    public encodeValue(value: BigNumber): Buffer {
+    public encodeValue(value_: BigNumber | string | number): Buffer {
+        const value = new BigNumber(value_, 10);
         if (value.greaterThan(this.getMaxValue())) {
             throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
         } else if (value.lessThan(this.getMinValue())) {
@@ -465,6 +466,7 @@ export class SolArray extends MemberDataType {
 export class Method extends MemberDataType {
     private methodSignature: string;
     private methodSelector: string;
+    private returnDataTypes: DataType[];
 
     // TMP
     public selector: string;
@@ -473,7 +475,11 @@ export class Method extends MemberDataType {
         super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
         this.methodSignature = this.computeSignature();
         this.selector = this.methodSelector = this.computeSelector();
-
+        this.returnDataTypes = [];
+        const dummy = new Byte({ type: 'byte', name: 'DUMMY' }); // @TODO TMP
+        _.each(abi.outputs, (dataItem: DataItem) => {
+            this.returnDataTypes.push(this.getFactory().create(dataItem, dummy));
+        });
     }
 
     private computeSignature(): string {
@@ -501,6 +507,23 @@ export class Method extends MemberDataType {
         return value;
     }
 
+    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
+        //console.log('O'.repeat(100), '\n', returndata, '\n', this.returnDataTypes, 'P'.repeat(100));
+
+        const returnValues: any[] = [];
+        const rules_ = rules ? rules : { structsAsObjects: false } as DecodingRules;
+        const rawReturnData = new RawCalldata(returndata, false);
+        _.each(this.returnDataTypes, (dataType: DataType) => {
+            returnValues.push(dataType.generateValue(rawReturnData, rules_));
+        });
+
+        //console.log('*'.repeat(40), '\n', JSON.stringify(returnValues), '\n', '*'.repeat(100));
+        /*if (returnValues.length === 1) {
+            return returnValues[0];
+        }*/
+        return returnValues;
+    }
+
     public getSignature(): string {
         return this.methodSignature;
     }
@@ -538,12 +561,15 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         throw new Error(`Unrecognized data type: '${dataItem.type}'`);
     }
 
-    public create(dataItem: DataItem, parentDataType: DataType): DataType {
+    public create(dataItem: DataItem, parentDataType?: DataType): DataType {
         const dataType = this.mapDataItemToDataType(dataItem);
         if (dataType.isStatic()) {
             return dataType;
         }
 
+        if (parentDataType === undefined) { // @Todo -- will this work for return values?
+            throw new Error(`Trying to create a pointer`);
+        }
         const pointer = new Pointer(dataType, parentDataType);
         return pointer;
     }
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 8d78b61b5..8add41af6 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -15,6 +15,35 @@ describe.only('ABI Encoder', () => {
 
     describe.only('ABI Tests at Method Level', () => {
 
+        it.only('Should reuse duplicated strings in string array', async () => {
+            const method = new AbiEncoder.Method(AbiSamples.GAbi);
+
+            const args = [
+                {
+                    a: new BigNumber(5),
+                    e: '0x616161',
+                    b: 'aaa',
+                    f: '0xe41d2489571d322189246dafa5ebde1f4699f498'
+                }
+            ]
+
+            // Verify optimized calldata is expected
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            //const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
+            //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+
+            // Verify args decode properly
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            //expect(decodedArgsJson).to.be.equal(argsJson);
+
+            console.log(method.getSignature());
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
+            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
+
+        });
+
         it('Should reuse duplicated strings in string array', async () => {
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
             const strings = [
diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts
index 5e8268f1a..aa38711cd 100644
--- a/packages/utils/test/abi_samples.ts
+++ b/packages/utils/test/abi_samples.ts
@@ -34,6 +34,40 @@ export const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
+
+export const GAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [{
+                name: 'a',
+                type: 'uint256',
+            },
+            {
+                name: 'b',
+                type: 'string',
+            },
+            {
+                name: 'e',
+                type: 'bytes',
+            },
+            {
+                name: 'f',
+                type: 'address',
+            }],
+
+            name: 'f',
+            type: 'tuple',
+
+        }
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const optimizerAbi2 = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From 880540f4b8fd8dd7a7f1a93cf7fbcdc17e1fbb13 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 10:34:04 -0800
Subject: Fixed issue with decoding negative ints with width < 256

---
 packages/utils/src/abi_encoder/data_type.ts      |   4 +-
 packages/utils/src/abi_encoder/evm_data_types.ts |   5 +-
 packages/utils/test/abi_encoder_test.ts          | 475 ++++++++++++-----------
 3 files changed, 246 insertions(+), 238 deletions(-)

diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index f5a8087ea..15de12a2f 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -41,7 +41,8 @@ export abstract class DataType {
     }
 
     public decode(calldata: string, rules?: DecodingRules): any {
-        const rawCalldata = new RawCalldata(calldata);
+        const rawCalldata = new RawCalldata(calldata, false);
+        console.log(`HERE DUDE ${JSON.stringify(rawCalldata)}`);
         const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
@@ -277,6 +278,7 @@ export abstract class MemberDataType extends DataType {
             value = [];
             _.each(members, (member: DataType, idx: number) => {
                 let memberValue = member.generateValue(calldata, rules);
+                console.log(`MEMBER VALUE: ${memberValue}`);
                 (value as any[]).push(memberValue);
             });
         }
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index d024a9bfa..bfb2808da 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -154,9 +154,8 @@ abstract class Number extends PayloadDataType {
         if (this instanceof Int) {
             // Check if we're negative
             const binBase = 2;
-            const paddedValueBin = value.toString(binBase);
-            const valueBin = paddedValueBin.slice(paddedValueBin.length - this.width);
-            if (valueBin[0].startsWith('1')) {
+            const valueBin = value.toString(2);
+            if (valueBin.length === 256 && valueBin[0].startsWith('1')) {
                 // Negative
                 // Step 1/3: Invert binary value
                 let invertedValueBin = '';
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 8add41af6..d2d7b9825 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -13,9 +13,9 @@ describe.only('ABI Encoder', () => {
 
     });
 
-    describe.only('ABI Tests at Method Level', () => {
+    describe('ABI Tests at Method Level', () => {
 
-        it.only('Should reuse duplicated strings in string array', async () => {
+        it('Should reuse duplicated strings in string array', async () => {
             const method = new AbiEncoder.Method(AbiSamples.GAbi);
 
             const args = [
@@ -723,237 +723,244 @@ describe.only('ABI Encoder', () => {
             expect(calldata).to.be.equal(expectedCalldata);
         });
     });
-    /*
-        describe('Array', () => {
-            it('sample', async () => {
-                const testDataItem = { name: 'testArray', type: 'int[2]' };
-                const dataType = new AbiEncoder.SolArray(testDataItem);
-                console.log(JSON.stringify(dataType, null, 4));
-                console.log('*'.repeat(60));
-                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-                console.log(JSON.stringify(dataType, null, 4));
-                const hexValue = dataType.getHexValue();
-                console.log('*'.repeat(60));
-                console.log(hexValue);
-            });
-    
-            it('sample undefined size', async () => {
-                const testDataItem = { name: 'testArray', type: 'int[]' };
-                const dataType = new AbiEncoder.SolArray(testDataItem);
-                console.log(JSON.stringify(dataType, null, 4));
-                console.log('*'.repeat(60));
-                dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-                console.log(JSON.stringify(dataType, null, 4));
-                const hexValue = dataType.getHexValue();
-                console.log('*'.repeat(60));
-                console.log(hexValue);
-            });
-    
-            it('sample dynamic types', async () => {
-                const testDataItem = { name: 'testArray', type: 'string[]' };
-                const dataType = new AbiEncoder.SolArray(testDataItem);
-                console.log(JSON.stringify(dataType, null, 4));
-                console.log('*'.repeat(60));
-                dataType.assignValue(['five', 'six', 'seven']);
-                console.log(JSON.stringify(dataType, null, 4));
-                const hexValue = dataType.getHexValue();
-                console.log('*'.repeat(60));
-                console.log(hexValue);
-                const calldata = new AbiEncoder.Calldata('0x01020304', 1);
-                dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
-                console.log('*'.repeat(60));
-                console.log(calldata.getHexValue());
-            });
-        });
-    
-        describe('Address', () => {
-            const testAddressDataItem = { name: 'testAddress', type: 'address' };
-            it('Valid Address', async () => {
-                const addressDataType = new AbiEncoder.Address(testAddressDataItem);
-                addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
-                const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
-    
-                console.log(addressDataType.getHexValue());
-                console.log(expectedAbiEncodedAddress);
-                expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
-            });
-        });
-    
-        describe('Bool', () => {
-            const testBoolDataItem = { name: 'testBool', type: 'bool' };
-            it('True', async () => {
-                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-                boolDataType.assignValue(true);
-                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
-                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
-            });
-    
-            it('False', async () => {
-                const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-                boolDataType.assignValue(false);
-                const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
-                expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
-            });
-        });
-    
-        describe('Integer', () => {
-            const testIntDataItem = { name: 'testInt', type: 'int' };
-            it('Positive - Base case', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(1));
-                const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            it('Positive', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(437829473));
-                const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            it('Negative - Base case', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(-1));
-                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            it('Negative', async () => {
-                const intDataType = new AbiEncoder.Int(testIntDataItem);
-                intDataType.assignValue(new BigNumber(-437829473));
-                const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
-                expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
-            });
-    
-            // TODO: Add bounds tests + tests for different widths
-        });
-    
-        describe('Unsigned Integer', () => {
-            const testIntDataItem = { name: 'testUInt', type: 'uint' };
-            it('Lower Bound', async () => {
-                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-                uintDataType.assignValue(new BigNumber(0));
-                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
-                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-            });
-    
-            it('Base Case', async () => {
-                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-                uintDataType.assignValue(new BigNumber(1));
-                const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-            });
-    
-            it('Random value', async () => {
-                const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-                uintDataType.assignValue(new BigNumber(437829473));
-                const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-                expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
-            });
-    
-            // TODO: Add bounds tests + tests for different widths
-        });
-    
-        describe('Static Bytes', () => {
-            it('Byte (padded)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x05');
-                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it.skip('Byte (no padding)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-    
-                // @TODO: This does not catch the Error
-                expect(byteDataType.assignValue('0x5')).to.throw();
-            });
-    
-            it('Bytes1', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x05');
-                const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it('Bytes32 (padded)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
-                const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it('Bytes32 (unpadded)', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-                byteDataType.assignValue('0x1a18bf61');
-                const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-                expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
-            });
-    
-            it.skip('Bytes32 - Too long', async () => {
-                const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-                const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-    
-                // @TODO: This does not catch the Error
-                expect(
-                    byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
-                ).to.throw(
-                    `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
-                );
-            });
-        });
-    
-        describe('Bytes (Dynamic)', () => {
-            const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
-            it('Less than 32 bytes', async () => {
-                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-                bytesDataType.assignValue('0x010203');
-                const expectedAbiEncodedBytes =
-                    '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
-    
-                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
-            });
-    
-            it('Greater than 32 bytes', async () => {
-                const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-                const testValue = '0x' + '61'.repeat(40);
-                bytesDataType.assignValue(testValue);
-                const expectedAbiEncodedBytes =
-                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-                expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
-            });
-    
-            // @TODO: Add test for throw on half-byte
-            // @TODO: Test with no 0x prefix
-            // @TODO: Test with Buffer as input
-        });
-    
-        describe('String', () => {
-            const testStringDataItem = { name: 'testString', type: 'string' };
-            it('Less than 32 bytes', async () => {
-                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-                stringDataType.assignValue('five');
-                const expectedAbiEncodedString =
-                    '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-    
-                console.log(stringDataType.getHexValue());
-                console.log(expectedAbiEncodedString);
-                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
-            });
-    
-            it('Greater than 32 bytes', async () => {
-                const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-                const testValue = 'a'.repeat(40);
-                stringDataType.assignValue(testValue);
-                const expectedAbiEncodedString =
-                    '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-                expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
-            });
+
+    describe.only('Array', () => {
+        it.only('sample', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'int[2]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const args = [new BigNumber(5), new BigNumber(6)];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        /*
+        it('sample undefined size', async () => {
+            const testDataItem = { name: 'testArray', type: 'int[]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            console.log(JSON.stringify(dataType, null, 4));
+            console.log('*'.repeat(60));
+            dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
+            console.log(JSON.stringify(dataType, null, 4));
+            const hexValue = dataType.getHexValue();
+            console.log('*'.repeat(60));
+            console.log(hexValue);
+        });
+
+        it('sample dynamic types', async () => {
+            const testDataItem = { name: 'testArray', type: 'string[]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            console.log(JSON.stringify(dataType, null, 4));
+            console.log('*'.repeat(60));
+            dataType.assignValue(['five', 'six', 'seven']);
+            console.log(JSON.stringify(dataType, null, 4));
+            const hexValue = dataType.getHexValue();
+            console.log('*'.repeat(60));
+            console.log(hexValue);
+            const calldata = new AbiEncoder.Calldata('0x01020304', 1);
+            dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
+            console.log('*'.repeat(60));
+            console.log(calldata.getHexValue());
         });*/
+    });
+
+    /*
+    describe('Address', () => {
+        const testAddressDataItem = { name: 'testAddress', type: 'address' };
+        it('Valid Address', async () => {
+            const addressDataType = new AbiEncoder.Address(testAddressDataItem);
+            addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
+            const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+
+            console.log(addressDataType.getHexValue());
+            console.log(expectedAbiEncodedAddress);
+            expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
+        });
+    });
+
+    describe('Bool', () => {
+        const testBoolDataItem = { name: 'testBool', type: 'bool' };
+        it('True', async () => {
+            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+            boolDataType.assignValue(true);
+            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+        });
+
+        it('False', async () => {
+            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
+            boolDataType.assignValue(false);
+            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
+            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+        });
+    });
+
+    describe('Integer', () => {
+        const testIntDataItem = { name: 'testInt', type: 'int' };
+        it('Positive - Base case', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(1));
+            const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        it('Positive', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(437829473));
+            const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        it('Negative - Base case', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(-1));
+            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        it('Negative', async () => {
+            const intDataType = new AbiEncoder.Int(testIntDataItem);
+            intDataType.assignValue(new BigNumber(-437829473));
+            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
+            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        });
+
+        // TODO: Add bounds tests + tests for different widths
+    });
+
+    describe('Unsigned Integer', () => {
+        const testIntDataItem = { name: 'testUInt', type: 'uint' };
+        it('Lower Bound', async () => {
+            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+            uintDataType.assignValue(new BigNumber(0));
+            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
+            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        });
+
+        it('Base Case', async () => {
+            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+            uintDataType.assignValue(new BigNumber(1));
+            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        });
+
+        it('Random value', async () => {
+            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
+            uintDataType.assignValue(new BigNumber(437829473));
+            const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
+            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        });
+
+        // TODO: Add bounds tests + tests for different widths
+    });
+
+    describe('Static Bytes', () => {
+        it('Byte (padded)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x05');
+            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it.skip('Byte (no padding)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+
+            // @TODO: This does not catch the Error
+            expect(byteDataType.assignValue('0x5')).to.throw();
+        });
+
+        it('Bytes1', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x05');
+            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it('Bytes32 (padded)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
+            const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it('Bytes32 (unpadded)', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+            byteDataType.assignValue('0x1a18bf61');
+            const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        });
+
+        it.skip('Bytes32 - Too long', async () => {
+            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
+            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+
+            // @TODO: This does not catch the Error
+            expect(
+                byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
+            ).to.throw(
+                `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
+            );
+        });
+    });
+
+    describe('Bytes (Dynamic)', () => {
+        const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
+        it('Less than 32 bytes', async () => {
+            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+            bytesDataType.assignValue('0x010203');
+            const expectedAbiEncodedBytes =
+                '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
+
+            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+        });
+
+        it('Greater than 32 bytes', async () => {
+            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
+            const testValue = '0x' + '61'.repeat(40);
+            bytesDataType.assignValue(testValue);
+            const expectedAbiEncodedBytes =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+        });
+
+        // @TODO: Add test for throw on half-byte
+        // @TODO: Test with no 0x prefix
+        // @TODO: Test with Buffer as input
+    });
+
+    describe('String', () => {
+        const testStringDataItem = { name: 'testString', type: 'string' };
+        it('Less than 32 bytes', async () => {
+            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+            stringDataType.assignValue('five');
+            const expectedAbiEncodedString =
+                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+
+            console.log(stringDataType.getHexValue());
+            console.log(expectedAbiEncodedString);
+            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+        });
+
+        it('Greater than 32 bytes', async () => {
+            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
+            const testValue = 'a'.repeat(40);
+            stringDataType.assignValue(testValue);
+            const expectedAbiEncodedString =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+        });
+    });*/
 });
-- 
cgit v1.2.3


From bc538c71fcab68578a82b08b4467240f8e79b96b Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 10:44:17 -0800
Subject: Tests - Encode/Decode Array

---
 packages/utils/src/abi_encoder/data_type.ts |  4 +-
 packages/utils/test/abi_encoder_test.ts     | 68 +++++++++++++++++++----------
 2 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 15de12a2f..022f5621f 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -41,8 +41,7 @@ export abstract class DataType {
     }
 
     public decode(calldata: string, rules?: DecodingRules): any {
-        const rawCalldata = new RawCalldata(calldata, false);
-        console.log(`HERE DUDE ${JSON.stringify(rawCalldata)}`);
+        const rawCalldata = new RawCalldata(calldata, false); // @TODO Sohuld not hardcode false here
         const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
@@ -278,7 +277,6 @@ export abstract class MemberDataType extends DataType {
             value = [];
             _.each(members, (member: DataType, idx: number) => {
                 let memberValue = member.generateValue(calldata, rules);
-                console.log(`MEMBER VALUE: ${memberValue}`);
                 (value as any[]).push(memberValue);
             });
         }
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index d2d7b9825..bf6250713 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -725,7 +725,7 @@ describe.only('ABI Encoder', () => {
     });
 
     describe.only('Array', () => {
-        it.only('sample', async () => {
+        it.only('Fixed size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[2]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
@@ -742,34 +742,56 @@ describe.only('ABI Encoder', () => {
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        /*
-        it('sample undefined size', async () => {
+        it.only('Dynamic size; Static elements', async () => {
+            // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
-            console.log(JSON.stringify(dataType, null, 4));
-            console.log('*'.repeat(60));
-            dataType.assignValue([new BigNumber(5), new BigNumber(6)]);
-            console.log(JSON.stringify(dataType, null, 4));
-            const hexValue = dataType.getHexValue();
-            console.log('*'.repeat(60));
-            console.log(hexValue);
+            // Construct args to be encoded
+            const args = [new BigNumber(5), new BigNumber(6)];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('sample dynamic types', async () => {
+        it.only('Fixed size; Dynamic elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[2]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const args = ["Hello", "world"];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it.only('Dynamic size; Dynamic elements', async () => {
+            // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
-            console.log(JSON.stringify(dataType, null, 4));
-            console.log('*'.repeat(60));
-            dataType.assignValue(['five', 'six', 'seven']);
-            console.log(JSON.stringify(dataType, null, 4));
-            const hexValue = dataType.getHexValue();
-            console.log('*'.repeat(60));
-            console.log(hexValue);
-            const calldata = new AbiEncoder.Calldata('0x01020304', 1);
-            dataType.bind(calldata, AbiEncoder.CalldataSection.PARAMS);
-            console.log('*'.repeat(60));
-            console.log(calldata.getHexValue());
-        });*/
+            // Construct args to be encoded
+            const args = ["Hello", "world"];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
     });
 
     /*
-- 
cgit v1.2.3


From a630312074758b31951c194533dcae596424592d Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 10:57:08 -0800
Subject: Tests for Tuple

---
 packages/utils/test/abi_encoder_test.ts | 67 ++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 5 deletions(-)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index bf6250713..cf1f0327a 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -4,6 +4,7 @@ import 'mocha';
 import { chaiSetup } from './utils/chai_setup';
 import { BigNumber, AbiEncoder } from '../src/';
 import * as AbiSamples from './abi_samples';
+import { DecodingRules } from '../src/abi_encoder';
 
 chaiSetup.configure();
 const expect = chai.expect;
@@ -724,8 +725,8 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Array', () => {
-        it.only('Fixed size; Static elements', async () => {
+    describe('Array', () => {
+        it('Fixed size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[2]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
@@ -742,7 +743,7 @@ describe.only('ABI Encoder', () => {
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it.only('Dynamic size; Static elements', async () => {
+        it('Dynamic size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
@@ -759,7 +760,7 @@ describe.only('ABI Encoder', () => {
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it.only('Fixed size; Dynamic elements', async () => {
+        it('Fixed size; Dynamic elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[2]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
@@ -776,7 +777,7 @@ describe.only('ABI Encoder', () => {
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it.only('Dynamic size; Dynamic elements', async () => {
+        it('Dynamic size; Dynamic elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
@@ -794,6 +795,62 @@ describe.only('ABI Encoder', () => {
         });
     });
 
+    describe.only('Tuple', () => {
+        it('Static elements only', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Tuple', type: 'tuple', components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }] };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: new BigNumber(-5), field_2: true };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('Dynamic elements only', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Tuple', type: 'tuple', components: [{ name: 'field_1', type: 'string' }, { name: 'field_2', type: 'bytes' }] };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: "Hello, World!", field_2: '0xabcdef0123456789' };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('Static and dynamic elements mixed', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Tuple', type: 'tuple', components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'string' }, { name: 'field_3', type: 'bool' }, { name: 'field_4', type: 'bytes' }] };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: new BigNumber(-5), field_2: "Hello, World!", field_3: true, field_4: '0xabcdef0123456789' };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+    });
+
     /*
     describe('Address', () => {
         const testAddressDataItem = { name: 'testAddress', type: 'address' };
-- 
cgit v1.2.3


From a2ad15be0dc500fa196021a5b32e80af8500043c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 11:18:34 -0800
Subject: Tests for Address

---
 packages/utils/src/abi_encoder/calldata.ts       | 15 +++++--
 packages/utils/src/abi_encoder/data_type.ts      |  2 +-
 packages/utils/src/abi_encoder/evm_data_types.ts | 13 +++++-
 packages/utils/test/abi_encoder_test.ts          | 52 +++++++++++++++++++-----
 4 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 078767c22..11288064e 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -248,7 +248,7 @@ export class Calldata {
     private selector: string;
     private rules: EncodingRules;
     private sizeInBytes: number;
-    private root: MemberCalldataBlock | undefined;
+    private root: CalldataBlock | undefined;
 
     constructor(rules: EncodingRules) {
         this.selector = '';
@@ -257,8 +257,17 @@ export class Calldata {
         this.root = undefined;
     }
 
-    private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> {
+    private createQueue(block: CalldataBlock): Queue<CalldataBlock> {
         const blockQueue = new Queue<CalldataBlock>();
+
+        // Base Case
+        if (block instanceof MemberCalldataBlock === false) {
+            blockQueue.push(block);
+            return blockQueue;
+        }
+
+        // This is a Member Block
+        const memberBlock = block as MemberCalldataBlock;
         _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
             if (member instanceof MemberCalldataBlock) {
                 blockQueue.mergeFront(this.createQueue(member));
@@ -429,7 +438,7 @@ export class Calldata {
         return "";
     }
 
-    public setRoot(block: MemberCalldataBlock) {
+    public setRoot(block: CalldataBlock) {
         this.root = block;
         this.sizeInBytes += block.getSizeInBytes();
     }
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 022f5621f..0f3cecac5 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -35,7 +35,7 @@ export abstract class DataType {
         const calldata = new Calldata(rules_);
         if (selector) calldata.setSelector(selector);
         const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
+        calldata.setRoot(block); // @TODO CHANGE
         const calldataHex = calldata.toHexString();
         return calldataHex;
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index bfb2808da..1ee95863b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -20,6 +20,8 @@ export interface DataTypeStaticInterface {
 
 export class Address extends PayloadDataType {
     private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
+    public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = "Address must be 20 bytes";
 
     constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
@@ -36,9 +38,16 @@ export class Address extends PayloadDataType {
         return type === 'address';
     }
 
-    public encodeValue(value: boolean): Buffer {
+    public encodeValue(value: string): Buffer {
+        if (value.startsWith('0x') === false) {
+            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+        }
+        const valueAsBuffer = ethUtil.toBuffer(value);
+        if (valueAsBuffer.byteLength !== 20) {
+            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
+        }
         const evmWordWidth = 32;
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth);
+        const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, evmWordWidth);
         return encodedValueBuf;
     }
 
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index cf1f0327a..5b341545e 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -725,7 +725,7 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe('Array', () => {
+    describe.only('Array', () => {
         it('Fixed size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[2]' };
@@ -793,6 +793,9 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
+
+        // @TODO: Add test that fails if we pass in the wrong number of elements
+        // @TODO: Add test that fails if we pass in an element of incorrecrt type
     });
 
     describe.only('Tuple', () => {
@@ -849,22 +852,51 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
+
+        // @TODO: Add test that fails if we pass in the wrong number of elements
+        // @TODO: Add test that fails if we pass in arguments in wrong order
     });
 
-    /*
-    describe('Address', () => {
-        const testAddressDataItem = { name: 'testAddress', type: 'address' };
+    describe.only('Address', () => {
         it('Valid Address', async () => {
-            const addressDataType = new AbiEncoder.Address(testAddressDataItem);
-            addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498');
-            const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+            // Create DataType object
+            const testDataItem = { name: 'Address', type: 'address' };
+            const dataType = new AbiEncoder.Address(testDataItem);
+            // Construct args to be encoded
+            const args = '0xe41d2489571d322189246dafa5ebde1f4699f498';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-            console.log(addressDataType.getHexValue());
-            console.log(expectedAbiEncodedAddress);
-            expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress);
+        it('Invalid Address - input is not valid hex', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Address', type: 'address' };
+            const dataType = new AbiEncoder.Address(testDataItem);
+            // Construct args to be encoded
+            const args = 'e4';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+        });
+
+        it('Invalid Address - input is not 20 bytes', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Address', type: 'address' };
+            const dataType = new AbiEncoder.Address(testDataItem);
+            // Construct args to be encoded
+            const args = '0xe4';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
         });
     });
 
+    /*
     describe('Bool', () => {
         const testBoolDataItem = { name: 'testBool', type: 'bool' };
         it('True', async () => {
-- 
cgit v1.2.3


From b28f26916fc51fa13308f335e3cd0bd5d3b075fc Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 11:20:35 -0800
Subject: Tests for Bool

---
 packages/utils/test/abi_encoder_test.ts | 43 ++++++++++++++++++++++++---------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 5b341545e..123ebe11d 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -896,24 +896,43 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    /*
-    describe('Bool', () => {
-        const testBoolDataItem = { name: 'testBool', type: 'bool' };
+    describe.only('Bool', () => {
         it('True', async () => {
-            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-            boolDataType.assignValue(true);
-            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+            // Create DataType object
+            const testDataItem = { name: 'Boolean', type: 'bool' };
+            const dataType = new AbiEncoder.Bool(testDataItem);
+            // Construct args to be encoded
+            const args = true;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
         it('False', async () => {
-            const boolDataType = new AbiEncoder.Bool(testBoolDataItem);
-            boolDataType.assignValue(false);
-            const expectedAbiEncodedBool = '0x0000000000000000000000000000000000000000000000000000000000000000';
-            expect(boolDataType.getHexValue()).to.be.equal(expectedAbiEncodedBool);
+            // Create DataType object
+            const testDataItem = { name: 'Boolean', type: 'bool' };
+            const dataType = new AbiEncoder.Bool(testDataItem);
+            // Construct args to be encoded
+            const args = false;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
     });
 
+    /*
     describe('Integer', () => {
         const testIntDataItem = { name: 'testInt', type: 'int' };
         it('Positive - Base case', async () => {
@@ -1073,5 +1092,5 @@ describe.only('ABI Encoder', () => {
                 '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
             expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
         });
-    });*/
+    }); */
 });
-- 
cgit v1.2.3


From 666075a87e8f7dfd5ef3553c5f8e08d826ac0641 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 11:47:32 -0800
Subject: Tests for Integer (tested 256 / 32 bit integers)

---
 packages/utils/src/abi_encoder/evm_data_types.ts |   4 +-
 packages/utils/test/abi_encoder_test.ts          | 202 ++++++++++++++++++++---
 2 files changed, 180 insertions(+), 26 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 1ee95863b..38878f63e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -118,9 +118,9 @@ abstract class Number extends PayloadDataType {
     public encodeValue(value_: BigNumber | string | number): Buffer {
         const value = new BigNumber(value_, 10);
         if (value.greaterThan(this.getMaxValue())) {
-            throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+            throw `Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
         } else if (value.lessThan(this.getMinValue())) {
-            throw `tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+            throw `Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
         }
 
         const hexBase = 16;
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 123ebe11d..21ad89711 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -932,40 +932,194 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    /*
-    describe('Integer', () => {
-        const testIntDataItem = { name: 'testInt', type: 'int' };
-        it('Positive - Base case', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(1));
-            const expectedAbiEncodedInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+    describe.only('Integer', () => {
+        it('Int256 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Positive', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(437829473));
-            const expectedAbiEncodedInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        it('Int256 - Negative Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(-1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Negative - Base case', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(-1));
-            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        it('Int256 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const max256BitInteger = (new BigNumber(2)).pow(255).minus(1);
+            const args = max256BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Negative', async () => {
-            const intDataType = new AbiEncoder.Int(testIntDataItem);
-            intDataType.assignValue(new BigNumber(-437829473));
-            const expectedAbiEncodedInt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5e7409f';
-            expect(intDataType.getHexValue()).to.be.equal(expectedAbiEncodedInt);
+        it('Int256 - Negative Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const min256BitInteger = (new BigNumber(2)).pow(255).times(-1);
+            const args = min256BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0x8000000000000000000000000000000000000000000000000000000000000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        // TODO: Add bounds tests + tests for different widths
+        it('Int256 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const max256BitInteger = (new BigNumber(2)).pow(255).minus(1);
+            const args = max256BitInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
+
+        it('Int256 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const min256BitInteger = (new BigNumber(2)).pow(255).times(-1);
+            const args = min256BitInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
+
+        it('Int32 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('Int32 - Negative Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(-1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('Int32 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const max32BitInteger = (new BigNumber(2)).pow(31).minus(1);
+            const args = max32BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000007fffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('Int32 - Negative Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const min32BitInteger = (new BigNumber(2)).pow(31).times(-1);
+            const args = min32BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('Int32 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const max32BitInteger = (new BigNumber(2)).pow(31).minus(1);
+            const args = max32BitInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
+
+        it('Int32 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const min32BitInteger = (new BigNumber(2)).pow(31).times(-1);
+            const args = min32BitInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
     });
 
+    /*
+
     describe('Unsigned Integer', () => {
         const testIntDataItem = { name: 'testUInt', type: 'uint' };
         it('Lower Bound', async () => {
-- 
cgit v1.2.3


From 9a0bd05c4ca98dd24d71cdbd53175bfdd5250107 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 11:55:56 -0800
Subject: Unsigned Integers

---
 packages/utils/test/abi_encoder_test.ts | 164 ++++++++++++++++++++++++++++----
 1 file changed, 145 insertions(+), 19 deletions(-)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 21ad89711..4b85ad938 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -1118,34 +1118,160 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    /*
+    describe.only('Unsigned Integer', () => {
+        it('UInt256 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('UInt256 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const max256BitUnsignedInteger = (new BigNumber(2)).pow(256).minus(1);
+            const args = max256BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('UInt256 - Zero Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const min256BitUnsignedInteger = new BigNumber(0);
+            const args = min256BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('UInt256 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const max256BitUnsignedInteger = (new BigNumber(2)).pow(256).minus(1);
+            const args = max256BitUnsignedInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
+
+        it('UInt256 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const min256BitUnsignedInteger = new BigNumber(0)
+            const args = min256BitUnsignedInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
+
+        it('UInt32 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-    describe('Unsigned Integer', () => {
-        const testIntDataItem = { name: 'testUInt', type: 'uint' };
-        it('Lower Bound', async () => {
-            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-            uintDataType.assignValue(new BigNumber(0));
-            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000000';
-            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        it('UInt32 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const max32BitUnsignedInteger = (new BigNumber(2)).pow(32).minus(1);
+            const args = max32BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000ffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Base Case', async () => {
-            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-            uintDataType.assignValue(new BigNumber(1));
-            const expectedAbiEncodedUInt = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        it('UInt32 - Zero Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const min32BitUnsignedInteger = new BigNumber(0);
+            const args = min32BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Random value', async () => {
-            const uintDataType = new AbiEncoder.UInt(testIntDataItem);
-            uintDataType.assignValue(new BigNumber(437829473));
-            const expectedAbiEncodedUInt = '0x000000000000000000000000000000000000000000000000000000001a18bf61';
-            expect(uintDataType.getHexValue()).to.be.equal(expectedAbiEncodedUInt);
+        it('UInt32 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const max32BitUnsignedInteger = (new BigNumber(2)).pow(32).minus(1);
+            const args = max32BitUnsignedInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
         });
 
-        // TODO: Add bounds tests + tests for different widths
+        it('UInt32 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const min32BitUnsignedInteger = new BigNumber(0);
+            const args = min32BitUnsignedInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw();
+        });
     });
 
+    /*
+
     describe('Static Bytes', () => {
         it('Byte (padded)', async () => {
             const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-- 
cgit v1.2.3


From d70d07366fcc9ed2a750a5427af9d210c486f344 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 12:43:16 -0800
Subject: Tests for Static Bytes

---
 packages/utils/src/abi_encoder/evm_data_types.ts |   4 +
 packages/utils/test/abi_encoder_test.ts          | 176 +++++++++++++++++------
 2 files changed, 140 insertions(+), 40 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 38878f63e..ff1bc594d 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -270,6 +270,10 @@ export class Byte extends PayloadDataType {
     }
 
     public encodeValue(value: string | Buffer): Buffer {
+        // Sanity check if string
+        if (typeof value === 'string' && value.startsWith('0x') === false) {
+            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
+        }
         // Convert value into a buffer and do bounds checking
         const valueBuf = ethUtil.toBuffer(value);
         if (valueBuf.byteLength > this.width) {
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 4b85ad938..5fe625092 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -1270,62 +1270,158 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    /*
+    describe.only('Static Bytes', () => {
+        it('Single Byte (byte)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Byte', type: 'byte' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x05';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-    describe('Static Bytes', () => {
-        it('Byte (padded)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x05');
-            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        it('Single Byte (bytes1)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes1', type: 'bytes1' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x05';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it.skip('Byte (no padding)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'byte' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+        it('4 Bytes (bytes4)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x00010203';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0001020300000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-            // @TODO: This does not catch the Error
-            expect(byteDataType.assignValue('0x5')).to.throw();
+        it('4 Bytes (bytes4); Encoder must pad input', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x1a18000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const paddedArgs = '0x1a180000';
+            const paddedArgsAsJson = JSON.stringify(paddedArgs);
+            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
         });
 
-        it('Bytes1', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes1' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x05');
-            const expectedAbiEncodedByte = '0x0500000000000000000000000000000000000000000000000000000000000000';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        it('32 Bytes (bytes32)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x0001020304050607080911121314151617181920212223242526272829303132';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0001020304050607080911121314151617181920212223242526272829303132';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+
+        it('32 Bytes (bytes32); Encoder must pad input', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18bf61';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const paddedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+            const paddedArgsAsJson = JSON.stringify(paddedArgs);
+            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
         });
 
-        it('Bytes32 (padded)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x0001020304050607080911121314151617181920212223242526272829303132');
-            const expectedAbiEncodedByte = '0x0001020304050607080911121314151617181920212223242526272829303132';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        it('Should throw when pass in too many bytes (bytes4)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x0102030405';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x0102030405 (5 bytes), which exceeds max bytes that can be stored in a bytes4');
         });
 
-        it('Bytes32 (unpadded)', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
-            byteDataType.assignValue('0x1a18bf61');
-            const expectedAbiEncodedByte = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-            expect(byteDataType.getHexValue()).to.be.equal(expectedAbiEncodedByte);
+        it('Should throw when pass in too many bytes (bytes32)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x010203040506070809101112131415161718192021222324252627282930313233';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x010203040506070809101112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32');
         });
 
-        it.skip('Bytes32 - Too long', async () => {
-            const testByteDataItem = { name: 'testStaticBytes', type: 'bytes32' };
-            const byteDataType = new AbiEncoder.Byte(testByteDataItem);
+        it('Should throw when pass in bad hex (no 0x prefix)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0102030405060708091011121314151617181920212223242526272829303132';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
+        });
 
-            // @TODO: This does not catch the Error
-            expect(
-                byteDataType.assignValue('0x000102030405060708091112131415161718192021222324252627282930313233'),
-            ).to.throw(
-                `Tried to assign 0x000102030405060708091112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32`,
-            );
+        it('Should throw when pass in bad hex (include a half-byte)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.Byte(testDataItem);
+            // Construct args to be encoded
+            const args = '0x010';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
         });
     });
 
+    /*
+
+    
+
     describe('Bytes (Dynamic)', () => {
         const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
         it('Less than 32 bytes', async () => {
-- 
cgit v1.2.3


From 5b187935dc6bf194555e1652dbf53d1c637d4add Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 13:01:26 -0800
Subject: tests for String

---
 packages/utils/src/abi_encoder/evm_data_types.ts |   4 +-
 packages/utils/test/abi_encoder_test.ts          | 160 +++++++++++++++++------
 2 files changed, 123 insertions(+), 41 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index ff1bc594d..b6a62a5d4 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -318,7 +318,7 @@ export class Bytes extends PayloadDataType {
 
     public encodeValue(value: string | Buffer): Buffer {
         if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Input value must be hex (prefixed with 0x). Actual value is '${value}'`);
+            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '${value}'`);
         }
         const valueBuf = ethUtil.toBuffer(value);
         if (value.length % 2 !== 0) {
@@ -365,7 +365,7 @@ export class SolString extends PayloadDataType {
     public encodeValue(value: string): Buffer {
         const wordsForValue = Math.ceil(value.length / 32);
         const paddedBytesForValue = wordsForValue * 32;
-        const valueBuf = ethUtil.setLengthRight(ethUtil.toBuffer(value), paddedBytesForValue);
+        const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedBytesForValue);
         const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
         const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
         return encodedValueBuf;
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 5fe625092..b541cd758 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -5,6 +5,7 @@ import { chaiSetup } from './utils/chai_setup';
 import { BigNumber, AbiEncoder } from '../src/';
 import * as AbiSamples from './abi_samples';
 import { DecodingRules } from '../src/abi_encoder';
+import ethUtil = require('ethereumjs-util');
 
 chaiSetup.configure();
 const expect = chai.expect;
@@ -1418,55 +1419,136 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    /*
-
-    
+    describe.only('Dynamic Bytes Dynamic', () => {
+        it('Fits into one EVM word', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.Bytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18bf61';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-    describe('Bytes (Dynamic)', () => {
-        const testBytesDataItem = { name: 'testBytes', type: 'bytes' };
-        it('Less than 32 bytes', async () => {
-            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-            bytesDataType.assignValue('0x010203');
-            const expectedAbiEncodedBytes =
-                '0x00000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000';
+        it('Spans multiple EVM words', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.Bytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x' + '61'.repeat(40);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+        it('Input as Buffer', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.Bytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18bf61';
+            const argsAsBuffer = ethUtil.toBuffer(args);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(argsAsBuffer);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Greater than 32 bytes', async () => {
-            const bytesDataType = new AbiEncoder.Bytes(testBytesDataItem);
-            const testValue = '0x' + '61'.repeat(40);
-            bytesDataType.assignValue(testValue);
-            const expectedAbiEncodedBytes =
-                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-            expect(bytesDataType.getHexValue()).to.be.equal(expectedAbiEncodedBytes);
+        it('Should throw when pass in bad hex (no 0x prefix)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.Bytes(testDataItem);
+            // Construct args to be encoded
+            const args = '01';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
         });
 
-        // @TODO: Add test for throw on half-byte
-        // @TODO: Test with no 0x prefix
-        // @TODO: Test with Buffer as input
+        it('Should throw when pass in bad hex (include a half-byte)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.Bytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x010';
+            // Encode Args and validate result
+            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
+        });
     });
 
-    describe('String', () => {
-        const testStringDataItem = { name: 'testString', type: 'string' };
-        it('Less than 32 bytes', async () => {
-            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-            stringDataType.assignValue('five');
-            const expectedAbiEncodedString =
-                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+    describe.only('String', () => {
+        it('Fits into one EVM word', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'String', type: 'string' };
+            const dataType = new AbiEncoder.SolString(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = 'five';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
 
-            console.log(stringDataType.getHexValue());
-            console.log(expectedAbiEncodedString);
-            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+        it('Spans multiple EVM words', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'String', type: 'string' };
+            const dataType = new AbiEncoder.SolString(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = 'a'.repeat(40);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
 
-        it('Greater than 32 bytes', async () => {
-            const stringDataType = new AbiEncoder.SolString(testStringDataItem);
-            const testValue = 'a'.repeat(40);
-            stringDataType.assignValue(testValue);
-            const expectedAbiEncodedString =
-                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-            expect(stringDataType.getHexValue()).to.be.equal(expectedAbiEncodedString);
+        it('String that begins with 0x prefix', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'String', type: 'string' };
+            const dataType = new AbiEncoder.SolString(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x' + 'a'.repeat(40);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-    }); */
+    });
 });
-- 
cgit v1.2.3


From b213cb39747ba0b78138d5a1db07b511bd9fd3b8 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 13:05:36 -0800
Subject: Temporary change for testing functions

---
 packages/utils/src/abi_encoder/data_type.ts | 2 +-
 packages/utils/test/abi_encoder_test.ts     | 9 +++------
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 0f3cecac5..21c08ef54 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -41,7 +41,7 @@ export abstract class DataType {
     }
 
     public decode(calldata: string, rules?: DecodingRules): any {
-        const rawCalldata = new RawCalldata(calldata, false); // @TODO Sohuld not hardcode false here
+        const rawCalldata = new RawCalldata(calldata, true); // @TODO Sohuld not hardcode false here
         const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index b541cd758..6d0d0c390 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -11,12 +11,7 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
-    describe.only('Optimizer', () => {
-
-    });
-
-    describe('ABI Tests at Method Level', () => {
-
+    describe('Optimizer', () => {
         it('Should reuse duplicated strings in string array', async () => {
             const method = new AbiEncoder.Method(AbiSamples.GAbi);
 
@@ -147,7 +142,9 @@ describe.only('ABI Encoder', () => {
             console.log(JSON.stringify(decodedArgs));
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
+    });
 
+    describe.only('ABI Tests at Method Level', () => {
         it('Crazy ABI', async () => {
             const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
             console.log(method.getSignature());
-- 
cgit v1.2.3


From 0c0bcb44d3ef6d68c9c7c05be25641ef57a7287a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 13:07:34 -0800
Subject: All 71 tests passing. Both for function encoding and individual
 types.

---
 packages/utils/src/abi_encoder/data_type.ts      | 4 ++--
 packages/utils/src/abi_encoder/evm_data_types.ts | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 21c08ef54..243b221ef 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -40,8 +40,8 @@ export abstract class DataType {
         return calldataHex;
     }
 
-    public decode(calldata: string, rules?: DecodingRules): any {
-        const rawCalldata = new RawCalldata(calldata, true); // @TODO Sohuld not hardcode false here
+    public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
+        const rawCalldata = new RawCalldata(calldata, hasSelector);
         const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index b6a62a5d4..2895ee00f 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -515,7 +515,8 @@ export class Method extends MemberDataType {
         if (!calldata.startsWith(this.selector)) {
             throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
         }
-        const value = super.decode(calldata, rules);
+        const hasSelector = true;
+        const value = super.decode(calldata, rules, hasSelector);
         return value;
     }
 
-- 
cgit v1.2.3


From 67dd062a2f6a936cad18ff81afac398cd6a1ab97 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 14:35:40 -0800
Subject: Cleaning up optimizer tests

---
 packages/utils/src/abi_encoder/calldata.ts       |   37 +-
 packages/utils/src/abi_encoder/data_type.ts      |   68 +-
 packages/utils/src/abi_encoder/evm_data_types.ts |   27 +-
 packages/utils/src/abi_encoder/index.ts          |    2 +-
 packages/utils/test/abi_encoder_test.ts          | 1085 +++++++++++-----------
 packages/utils/test/abi_samples.ts               |   73 +-
 6 files changed, 687 insertions(+), 605 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 11288064e..e6ce58957 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -20,7 +20,14 @@ export abstract class CalldataBlock {
     private relocatable: boolean;
     private parentName: string;
 
-    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ headerSizeInBytes: number, bodySizeInBytes: number, relocatable: boolean) {
+    constructor(
+        name: string,
+        signature: string,
+        parentName: string,
+        /*offsetInBytes: number,*/ headerSizeInBytes: number,
+        bodySizeInBytes: number,
+        relocatable: boolean,
+    ) {
         this.name = name;
         this.signature = signature;
         this.parentName = parentName;
@@ -91,7 +98,13 @@ export abstract class CalldataBlock {
 export class PayloadCalldataBlock extends CalldataBlock {
     private payload: Buffer;
 
-    constructor(name: string, signature: string, parentName: string, /*offsetInBytes: number,*/ relocatable: boolean, payload: Buffer) {
+    constructor(
+        name: string,
+        signature: string,
+        parentName: string,
+        /*offsetInBytes: number,*/ relocatable: boolean,
+        payload: Buffer,
+    ) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = payload.byteLength;
         super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
@@ -115,7 +128,14 @@ export class DependentCalldataBlock extends CalldataBlock {
     private dependency: CalldataBlock;
     private aliasFor: CalldataBlock | undefined;
 
-    constructor(name: string, signature: string, parentName: string, relocatable: boolean, dependency: CalldataBlock, parent: CalldataBlock) {
+    constructor(
+        name: string,
+        signature: string,
+        parentName: string,
+        relocatable: boolean,
+        dependency: CalldataBlock,
+        parent: CalldataBlock,
+    ) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
         super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
@@ -125,7 +145,8 @@ export class DependentCalldataBlock extends CalldataBlock {
     }
 
     public toBuffer(): Buffer {
-        const destinationOffset = (this.aliasFor !== undefined) ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
+        const destinationOffset =
+            this.aliasFor !== undefined ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
         const parentOffset = this.parent.getOffsetInBytes();
         const parentHeaderSize = this.parent.getHeaderSizeInBytes();
         const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
@@ -314,7 +335,7 @@ export class Calldata {
 
             //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
             //const parentOffset = name.lastIndexOf(parentName);
-            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');//.replace(`${parentName}[`, '[');
+            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, ''); //.replace(`${parentName}[`, '[');
             const signature = block.getSignature();
 
             // Current offset
@@ -383,7 +404,7 @@ export class Calldata {
         const blocksByHash: { [key: string]: CalldataBlock } = {};
 
         // 1. Create a queue of subtrees by hash
-        // Note that they are ordered the same as 
+        // Note that they are ordered the same as
         const subtreeQueue = this.createQueue(this.root);
         let block: CalldataBlock | undefined;
         while ((block = subtreeQueue.popBack()) !== undefined) {
@@ -435,7 +456,7 @@ export class Calldata {
     }
 
     public toAnnotatedString(): string {
-        return "";
+        return '';
     }
 
     public setRoot(block: CalldataBlock) {
@@ -532,4 +553,4 @@ export class RawCalldata {
     public getSelector(): string {
         return this.selector;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 243b221ef..80797c563 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -1,4 +1,11 @@
-import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
+import {
+    RawCalldata,
+    Calldata,
+    CalldataBlock,
+    PayloadCalldataBlock,
+    DependentCalldataBlock,
+    MemberCalldataBlock,
+} from './calldata';
 import { MethodAbi, DataItem } from 'ethereum-types';
 import { DecodingRules, EncodingRules } from './calldata';
 import { BigNumber } from '../configured_bignumber';
@@ -67,7 +74,13 @@ export abstract class PayloadDataType extends DataType {
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
         const relocatable = false;
-        const block = new PayloadCalldataBlock(name, signature, parentName, /*offsetInBytes,*/ relocatable, encodedValue);
+        const block = new PayloadCalldataBlock(
+            name,
+            signature,
+            parentName,
+            /*offsetInBytes,*/ relocatable,
+            encodedValue,
+        );
         return block;
     }
 
@@ -104,7 +117,14 @@ export abstract class DependentDataType extends DataType {
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
         const relocatable = false;
-        const block = new DependentCalldataBlock(name, signature, parentName, relocatable, dependencyBlock, parentBlock);
+        const block = new DependentCalldataBlock(
+            name,
+            signature,
+            parentName,
+            relocatable,
+            dependencyBlock,
+            parentBlock,
+        );
         return block;
     }
 
@@ -135,8 +155,13 @@ export abstract class MemberDataType extends DataType {
     protected arrayLength: number | undefined;
     protected arrayElementType: string | undefined;
 
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, isArray: boolean = false, arrayLength?: number, arrayElementType?: string) {
+    public constructor(
+        dataItem: DataItem,
+        factory: DataTypeFactory,
+        isArray: boolean = false,
+        arrayLength?: number,
+        arrayElementType?: string,
+    ) {
         super(dataItem, factory);
         this.memberMap = {};
         this.members = [];
@@ -207,11 +232,17 @@ export abstract class MemberDataType extends DataType {
         }
 
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
+            this.getDataItem().name,
+            this.getSignature(),
+            parentName,
+            this.isStatic(),
+            false,
+        );
 
         let members = this.members;
         if (this.isArray && this.arrayLength === undefined) {
-            [members,] = this.createMembersWithLength(this.getDataItem(), value.length);
+            [members] = this.createMembersWithLength(this.getDataItem(), value.length);
 
             const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
             methodBlock.setHeader(lenBuf);
@@ -228,12 +259,20 @@ export abstract class MemberDataType extends DataType {
 
     protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(this.getDataItem().name, this.getSignature(), parentName, this.isStatic(), false);
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
+            this.getDataItem().name,
+            this.getSignature(),
+            parentName,
+            this.isStatic(),
+            false,
+        );
         const memberBlocks: CalldataBlock[] = [];
         let childMap = _.cloneDeep(this.memberMap);
         _.forOwn(obj, (value: any, key: string) => {
             if (key in childMap === false) {
-                throw new Error(`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`);
+                throw new Error(
+                    `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
+                );
             }
             const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
             memberBlocks.push(block);
@@ -249,7 +288,10 @@ export abstract class MemberDataType extends DataType {
     }
 
     public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block = (value instanceof Array) ? this.generateCalldataBlockFromArray(value, parentBlock) : this.generateCalldataBlockFromObject(value, parentBlock);
+        const block =
+            value instanceof Array
+                ? this.generateCalldataBlockFromArray(value, parentBlock)
+                : this.generateCalldataBlockFromObject(value, parentBlock);
         return block;
     }
 
@@ -261,7 +303,7 @@ export abstract class MemberDataType extends DataType {
             const hexBase = 16;
             const arrayLength = new BigNumber(arrayLengthHex, hexBase);
 
-            [members,] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+            [members] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
         }
 
         calldata.startScope();
@@ -314,9 +356,9 @@ export abstract class MemberDataType extends DataType {
 
         // Search for dependent members
         const dependentMember = _.find(this.members, (member: DataType) => {
-            return (member instanceof DependentDataType);
+            return member instanceof DependentDataType;
         });
-        const isStatic = (dependentMember === undefined); // static if we couldn't find a dependent member
+        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
         return isStatic;
     }
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 2895ee00f..10e7b987b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -21,7 +21,7 @@ export interface DataTypeStaticInterface {
 export class Address extends PayloadDataType {
     private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
-    public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = "Address must be 20 bytes";
+    public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes';
 
     constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
@@ -88,7 +88,7 @@ export class Bool extends PayloadDataType {
         const valueBuf = calldata.popWord();
         const valueHex = ethUtil.bufferToHex(valueBuf);
         const valueNumber = new BigNumber(valueHex, 16);
-        let value: boolean = (valueNumber.equals(0)) ? false : true;
+        let value: boolean = valueNumber.equals(0) ? false : true;
         if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
             throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
         }
@@ -147,10 +147,7 @@ abstract class Number extends PayloadDataType {
             const negativeValue = invertedValue.plus(1);
 
             // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`),
-                evmWordWidth,
-            );
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`), evmWordWidth);
         }
 
         return valueBuf;
@@ -279,7 +276,7 @@ export class Byte extends PayloadDataType {
         if (valueBuf.byteLength > this.width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                valueBuf.byteLength
+                    valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
@@ -392,7 +389,6 @@ export class SolString extends PayloadDataType {
 }
 
 export class Pointer extends DependentDataType {
-
     constructor(destDataType: DataType, parentDataType: DataType) {
         const destDataItem = destDataType.getDataItem();
         const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
@@ -442,7 +438,7 @@ export class SolArray extends MemberDataType {
 
         const isArray = true;
         const arrayElementType = matches[1];
-        const arrayLength = (matches[2] === '') ? undefined : parseInt(matches[2], 10);
+        const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], 10);
         super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
         this.elementType = arrayElementType;
         this.arraySignature = this.computeSignature();
@@ -513,7 +509,9 @@ export class Method extends MemberDataType {
 
     public decode(calldata: string, rules?: DecodingRules): any[] | object {
         if (!calldata.startsWith(this.selector)) {
-            throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
+            throw new Error(
+                `Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`,
+            );
         }
         const hasSelector = true;
         const value = super.decode(calldata, rules, hasSelector);
@@ -524,7 +522,7 @@ export class Method extends MemberDataType {
         //console.log('O'.repeat(100), '\n', returndata, '\n', this.returnDataTypes, 'P'.repeat(100));
 
         const returnValues: any[] = [];
-        const rules_ = rules ? rules : { structsAsObjects: false } as DecodingRules;
+        const rules_ = rules ? rules : ({ structsAsObjects: false } as DecodingRules);
         const rawReturnData = new RawCalldata(returndata, false);
         _.each(this.returnDataTypes, (dataType: DataType) => {
             returnValues.push(dataType.generateValue(rawReturnData, rules_));
@@ -549,7 +547,7 @@ export class Method extends MemberDataType {
 export class EvmDataTypeFactory implements DataTypeFactory {
     private static instance: DataTypeFactory;
 
-    private constructor() { }
+    private constructor() {}
 
     public static getInstance(): DataTypeFactory {
         if (!EvmDataTypeFactory.instance) {
@@ -580,10 +578,11 @@ export class EvmDataTypeFactory implements DataTypeFactory {
             return dataType;
         }
 
-        if (parentDataType === undefined) { // @Todo -- will this work for return values?
+        if (parentDataType === undefined) {
+            // @Todo -- will this work for return values?
             throw new Error(`Trying to create a pointer`);
         }
         const pointer = new Pointer(dataType, parentDataType);
         return pointer;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts
index 991edb8c5..95ad84ac9 100644
--- a/packages/utils/src/abi_encoder/index.ts
+++ b/packages/utils/src/abi_encoder/index.ts
@@ -1,2 +1,2 @@
 export { EncodingRules, DecodingRules } from './calldata';
-export * from './evm_data_types';
\ No newline at end of file
+export * from './evm_data_types';
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 6d0d0c390..9925abcc3 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -12,273 +12,188 @@ const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
     describe('Optimizer', () => {
-        it('Should reuse duplicated strings in string array', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.GAbi);
-
-            const args = [
-                {
-                    a: new BigNumber(5),
-                    e: '0x616161',
-                    b: 'aaa',
-                    f: '0xe41d2489571d322189246dafa5ebde1f4699f498'
-                }
-            ]
-
-            // Verify optimized calldata is expected
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            //const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
-            //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-
-            // Verify args decode properly
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            //expect(decodedArgsJson).to.be.equal(argsJson);
-
-            console.log(method.getSignature());
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
-
-        });
-
-        it('Should reuse duplicated strings in string array', async () => {
+        it('Should reuse duplicate strings in string array', async () => {
+            // Description:
+            //   There are two unique values in the array `strings`.
+            //   There should exist only one copy of each string in the optimized calldata.
+            //   In unoptimized calldata, two copies of each string will be created.
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
-            const strings = [
-                "Test String",
-                "Test String 2",
-                "Test String",
-                "Test String 2",
-            ];
+            const strings = ['Test String', 'Test String 2', 'Test String', 'Test String 2'];
             const args = [strings];
-
-            // Verify optimized calldata is expected
+            // Validate calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
+            const expectedOptimizedCalldata =
+                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-
-            // Verify args decode properly
+            // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
-
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
         });
-
-        it('Should point array elements to a duplicated value from another parameter', async () => {
+        it('Should point array elements to a duplicate value from another parameter', async () => {
+            // Description:
+            //   There are two unique values in the array `strings`.
+            //   The value "Test String" appears three times in this array.
+            //   There should exist only one copy of this string in the optimized calldata.
+            //   In unoptimized calldata, "Test String" would be written three times.
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
-            const stringArray = [
-                "Test String",
-                "Test String",
-                "Test String",
-                "Test String 2",
-            ];
+            const strings = ['Test String', 'Test String', 'Test String', 'Test String 2'];
             const string = 'Test String';
-            const args = [stringArray, string];
-
-            // Verify optimized calldata is expected
+            const args = [strings, string];
+            // Validate calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata = '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000';
+            const expectedOptimizedCalldata =
+                '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-
-            // Verify args decode properly
+            // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
-
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100));
-            console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100));
         });
-
-
-        it('Optimizer #3 (tuple should point to array)', async () => {
+        it('Dynamic Array of uints should point to Dynamic Array of Tuple(Uint)s', async () => {
+            // Description:
+            //   There are two dynamic arrays, one of uint's and one of tuples.
+            //   Each tuple is simply a wrapper for a uint - tuple := {key: uintValue}
+            //   While the elements of these arrays have different types, they
+            //   have the same representation in calldata.
+            //   That is, a `uint` and a `tuple{uint}` both consume exactly one word of calldata.
+            //   In the optimized calldata, only the elements of one array should be included.
+            //   Both arrays will then point to the same set of elements.
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.optimizerAbi3);
-            const uint8Array = [
-                new BigNumber(100),
-                new BigNumber(150),
-                new BigNumber(200),
-                new BigNumber(225),
-            ];
+            const uint8Array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
             const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
             const args = [uint8Array, uintTupleArray];
-
-
-            const TEST = method.encode(args, { optimize: true, annotate: true });
-            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
-
+            // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
-
-            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const expectedOptimizedCalldata =
+                '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
-            console.log(JSON.stringify(decodedArgs));
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-
-        it('Optimizer #4 (Expect no optimization)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
-            const uint8Array = [
-                new BigNumber(100),
-                new BigNumber(150),
-                new BigNumber(200),
-                new BigNumber(225),
-            ];
-            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
-            const args = [uint8Array, uintTupleArray];
-
-
-            const TEST = method.encode(args, { optimize: true, annotate: true });
-            console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
-
+        it('Duplicate Dynamic Arrays', async () => {
+            // Description:
+            //   Two dynamic arrays with the same values.
+            //   In the optimized calldata, only one set of elements should be included.
+            //   Both arrays should point to this set.
+            // Generate calldata
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5);
+            const array1 = [new BigNumber(100), new BigNumber(150)];
+            const array2 = [array1[0], array1[1]];
+            const args = [array1, array2];
+            // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
-
-            console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
+            const expectedOptimizedCalldata =
+                '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
-            console.log(JSON.stringify(decodedArgs));
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-    });
 
-    describe.only('ABI Tests at Method Level', () => {
-        it('Crazy ABI', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.crazyAbi);
-            console.log(method.getSignature());
-
-            const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
-            const someStaticArrayWithDynamicMembers = [
-                'the little piping piper piped a piping pipper papper',
-                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-            ];
-            const someDynamicArrayWithDynamicMembers = [
-                '0x38745637834987324827439287423897238947239847',
-                '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
-                '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
-            ];
-            const some2DArray = [
-                [
-                    'some string',
-                    'some another string',
-                    'there are just too many stringsup in',
-                    'here',
-                    'yall ghonna make me lose my mind',
-                ],
-                [
-                    'the little piping piper piped a piping pipper papper',
-                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-                ],
-                [],
-            ];
-            const someTuple = {
-                someUint32: new BigNumber(4037824789),
-                someStr: 'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.'
-            };
-            const someTupleWithDynamicTypes = {
-                someUint: new BigNumber(4024789),
-                someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
-                someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
-                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
-            };
-            const someTupleWithDynamicTypes2 = {
-                someUint: new BigNumber(9024789),
-                someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
-                someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
-                someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
-            };
-            const someTupleWithDynamicTypes3 = {
-                someUint: new BigNumber(1024789),
-                someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
-                someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
-                someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
-            };
-            const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
-
-            const args = {
-                someStaticArray: someStaticArray,
-                someStaticArrayWithDynamicMembers: someStaticArrayWithDynamicMembers,
-                someDynamicArrayWithDynamicMembers: someDynamicArrayWithDynamicMembers,
-                some2DArray: some2DArray,
-                someTuple: someTuple,
-                someTupleWithDynamicTypes: someTupleWithDynamicTypes,
-                someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
-            };
-
-            const calldata = method.encode(args);
-            console.log(calldata);
-
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
-            console.log(method.getSignature());
-
-            const expectedCalldata = '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
-            //const expectedCalldata = '0x30e1f844000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cf5763d5ec63d500600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f7484848484848484848484848484848484848384757687980943399445858584893209100000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata, { structsAsObjects: true });
-            const decodedValueJson = JSON.stringify(decodedValue);
-            console.log(`DECODED`, '*'.repeat(200), '\n', decodedValueJson);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        /*
+        it.only('Duplicate Static Arrays', async () => {
+            // Description:
+            //   Two dynamic arrays with the same values.
+            //   In the optimized calldata, only one set of elements should be included.
+            //   Both arrays should point to this set.
+            // Generate calldata
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5);
+            const array1 = [new BigNumber(100), new BigNumber(150)];
+            const array2 = [array1[0], array1[1]];
+            const args = [array1, array2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
         });
 
-        it('Crazy ABI #1', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.crazyAbi1);
-
-            const args = [
-                new BigNumber(256745454),
-                new BigNumber(-256745454),
-                new BigNumber(434244),
-                '0x43',
-                '0x0001020304050607080911121314151617181920212223242526272829303132',
-                '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
-                'Little peter piper piped a piping pepper pot',
-                '0xe41d2489571d322189246dafa5ebde1f4699f498',
-                true
-            ];
-
-            const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
+        it.only('Duplicate Tuples', async () => {
+            // Description:
+            //   Two dynamic arrays with the same values.
+            //   In the optimized calldata, only one set of elements should be included.
+            //   Both arrays should point to this set.
+            // Generate calldata
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5);
+            const array1 = [new BigNumber(100), new BigNumber(150)];
+            const array2 = [array1[0], array1[1]];
+            const args = [array1, array2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });*/
 
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        it('Static Array of static types should not be optimized', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
+            const uint8Array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
+            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
+            const args = [uint8Array, uintTupleArray];
+            // Validate calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const unoptimizedCalldata = method.encode(args);
+            expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
         });
 
+        // Todo: Unfixed array points to fixed array
+        // Todo: Unfixed to unfixed array
+        // Todo: Duplicate tuples
+    });
 
+    describe('Method ABIs', () => {
         it('Types with default widths', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
-            console.log(method);
-            const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
+            const args = [
+                new BigNumber(1),
+                new BigNumber(-1),
+                '0x56',
+                [new BigNumber(1)],
+                [new BigNumber(-1)],
+                ['0x56'],
+            ];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
+            // Validate calldata
+            const expectedCalldata =
+                '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Array of Static Tuples (Array has defined length)', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
-
             let value = 0;
             const arrayOfTuples = [];
             for (let i = 0; i < 8; ++i) {
@@ -286,23 +201,19 @@ describe.only('ABI Encoder', () => {
             }
             const args = [arrayOfTuples];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+            // Validate calldata
+            const expectedCalldata =
+                '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Array of Static Tuples (Array has dynamic length)', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
-
             let value = 0;
             const arrayOfTuples = [];
             for (let i = 0; i < 8; ++i) {
@@ -310,316 +221,352 @@ describe.only('ABI Encoder', () => {
             }
             const args = [arrayOfTuples];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+            // Validate calldata
+            const expectedCalldata =
+                '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Array of Dynamic Tuples (Array has defined length)', async () => {
+            // Generate Calldata
             const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
-
             let value = 0;
             const arrayOfTuples = [];
             for (let i = 0; i < 8; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
+                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
             }
             const args = [arrayOfTuples];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+            // Validate calldata
+            const expectedCalldata =
+                '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
-
             let value = 0;
             const arrayOfTuples = [];
             for (let i = 0; i < 8; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), (new BigNumber(++value)).toString()]);
+                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
             }
             const args = [arrayOfTuples];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+            // Validate calldata
+            const expectedCalldata =
+                '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Multidimensional Arrays / Static Members', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
-
             // Eight 3-dimensional arrays of uint8[2][2][2]
             let value = 0;
             const args = [];
             for (let i = 0; i < 8; ++i) {
-                args.push(
+                args.push([
                     [
-                        [
-                            [new BigNumber(++value), new BigNumber(++value)],
-                            [new BigNumber(++value), new BigNumber(++value)],
-                        ],
-                        [
-                            [new BigNumber(++value), new BigNumber(++value)],
-                            [new BigNumber(++value), new BigNumber(++value)],
-                        ]
-                    ]
-                );
+                        [new BigNumber(++value), new BigNumber(++value)],
+                        [new BigNumber(++value), new BigNumber(++value)],
+                    ],
+                    [
+                        [new BigNumber(++value), new BigNumber(++value)],
+                        [new BigNumber(++value), new BigNumber(++value)],
+                    ],
+                ]);
             }
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; expect(calldata).to.be.equal(expectedCalldata);
+            // Validate calldata
+            const expectedCalldata =
+                '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            expect(calldata).to.be.equal(expectedCalldata);
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Multidimensional Arrays / Dynamic Members', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
-
             // Eight 3-dimensional arrays of string[2][2][2]
             let value = 0;
             const args = [];
             for (let i = 0; i < 4; ++i) {
-                args.push(
+                args.push([
                     [
-                        [
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                        ],
-                        [
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                            [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                        ]
-                    ]
-                );
+                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                    ],
+                    [
+                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                    ],
+                ]);
             }
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(method.getSignature());
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
+            // Validate calldata
+            const expectedCalldata =
+                '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
-        it('Fixed Lenfgth Array / Dynamic Members', async () => {
+        it('Fixed Length Array / Dynamic Members', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
-            const args = [["Brave", "New", "World"]];
+            const args = [['Brave', 'New', 'World']];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
+            // Validate calldata
             const expectedCalldata =
                 '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
-        it('Fixed Lenfgth Array / Dynamic Members', async () => {
+        it('Fixed Length Array / Dynamic Members', async () => {
+            // Generaet calldata
             const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
-            const args = [["Brave", "New", "World"]];
+            const args = [['Brave', 'New', 'World']];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
+            // Validate calldata
             const expectedCalldata =
                 '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Unfixed Length Array / Dynamic Members ABI', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
-            const args = [["Brave", "New", "World"]];
+            const args = [['Brave', 'New', 'World']];
             const calldata = method.encode(args);
-            console.log(calldata);
-            console.log('*'.repeat(40));
-            console.log(JSON.stringify(args));
-            const expectedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            // Validate calldata
+            const expectedCalldata =
+                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Unfixed Length Array / Static Members ABI', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
             const calldata = method.encode(args);
-            const expectedCalldata = '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+            // Validate calldata
+            const expectedCalldata =
+                '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
-
         it('Fixed Length Array / Static Members ABI', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
             const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
             const calldata = method.encode(args);
+            // Validate calldata
             const expectedCalldata =
                 '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-
-
-        it('Simple ABI 2', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.simpleAbi2);
-
-            const args = [
-                '0xaf', // e (bytes1)
-                '0x0001020304050607080911121314151617181920212223242526272829303132', // f (bytes32)
-                '0x616161616161616161616161616161616161616161616161616161616161616161616161616161611114f324567838475647382938475677448899338457668899002020202020', // g
-                'My first name is Greg and my last name is Hysen, what do ya know!', // h
-            ];
-
-            const calldata = method.encode(args);
-            const expectedCalldata =
-                '0x7ac2bd96af000000000000000000000000000000000000000000000000000000000000000001020304050607080911121314151617181920212223242526272829303132000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000047616161616161616161616161616161616161616161616161616161616161616161616161616161611114f3245678384756473829384756774488993384576688990020202020200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414d79206669727374206e616d65206973204772656720616e64206d79206c617374206e616d6520697320487973656e2c207768617420646f207961206b6e6f772100000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Array ABI', async () => {
+            // Generate calldata
             const method = new AbiEncoder.Method(AbiSamples.stringAbi);
-            console.log(method);
             const args = [['five', 'six', 'seven']];
             const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
+            // Validate calldata
             const expectedCalldata =
                 '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Static Tuple', async () => {
+            // Generate calldata
             // This is dynamic because it has dynamic members
             const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
             const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
             const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata = '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
+            // Validate calldata
+            const expectedCalldata =
+                '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Dynamic Tuple (Array input)', async () => {
+            // Generate calldata
             // This is dynamic because it has dynamic members
             const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
             const args = [[new BigNumber(5), 'five']];
             const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
+            // Validate calldata
             const expectedCalldata =
                 '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
-
-            // Test decoding
+            // Validate decoding
             const expectedDecodedValueJson = JSON.stringify(args);
             const decodedValue = method.decode(calldata);
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
         it('Dynamic Tuple (Object input)', async () => {
+            // Generate Calldata
             // This is dynamic because it has dynamic members
             const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five' }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
+            const args = [[new BigNumber(5), 'five']];
+            const calldata = method.encode(args);
+            // Validate calldata
             const expectedCalldata =
                 '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
             expect(calldata).to.be.equal(expectedCalldata);
+            // Validate decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+        it('Large, Flat ABI', async () => {
+            // Construct calldata
+            const method = new AbiEncoder.Method(AbiSamples.largeFlatAbi);
+            const args = [
+                new BigNumber(256745454),
+                new BigNumber(-256745454),
+                new BigNumber(434244),
+                '0x43',
+                '0x0001020304050607080911121314151617181920212223242526272829303132',
+                '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
+                'Little peter piper piped a piping pepper pot',
+                '0xe41d2489571d322189246dafa5ebde1f4699f498',
+                true,
+            ];
+            // Validate calldata
+            const calldata = method.encode(args);
+            const expectedCalldata =
+                '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+            // Validate decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata);
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        });
+        it('Large, Nested ABI', async () => {
+            // Construct Calldata
+            const method = new AbiEncoder.Method(AbiSamples.largeNestedAbi);
+            const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
+            const someStaticArrayWithDynamicMembers = [
+                'the little piping piper piped a piping pipper papper',
+                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+            ];
+            const someDynamicArrayWithDynamicMembers = [
+                '0x38745637834987324827439287423897238947239847',
+                '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
+                '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
+            ];
+            const some2DArray = [
+                [
+                    'some string',
+                    'some another string',
+                    'there are just too many stringsup in',
+                    'here',
+                    'yall ghonna make me lose my mind',
+                ],
+                [
+                    'the little piping piper piped a piping pipper papper',
+                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+                ],
+                [],
+            ];
+            const someTuple = {
+                someUint32: new BigNumber(4037824789),
+                someStr:
+                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+            };
+            const someTupleWithDynamicTypes = {
+                someUint: new BigNumber(4024789),
+                someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+                someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
+                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
+            };
+            const someTupleWithDynamicTypes2 = {
+                someUint: new BigNumber(9024789),
+                someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
+                someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
+                someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
+            };
+            const someTupleWithDynamicTypes3 = {
+                someUint: new BigNumber(1024789),
+                someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
+                someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
+                someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
+            };
+            const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
+            const args = {
+                someStaticArray: someStaticArray,
+                someStaticArrayWithDynamicMembers: someStaticArrayWithDynamicMembers,
+                someDynamicArrayWithDynamicMembers: someDynamicArrayWithDynamicMembers,
+                some2DArray: some2DArray,
+                someTuple: someTuple,
+                someTupleWithDynamicTypes: someTupleWithDynamicTypes,
+                someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes,
+            };
+            const calldata = method.encode(args);
+            // Validate calldata
+            const expectedCalldata =
+                '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
+            expect(calldata).to.be.equal(expectedCalldata);
+            // Validate decoding
+            const expectedDecodedValueJson = JSON.stringify(args);
+            const decodedValue = method.decode(calldata, { structsAsObjects: true });
+            const decodedValueJson = JSON.stringify(decodedValue);
+            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
 
+        // @TODO: Test Nested Tuples (Not Supported on )
+
         it.skip('Nested Tuples', async () => {
             // Couldn't get nested tuples to work with Remix
             // This is dynamic because it has dynamic members
@@ -628,8 +575,8 @@ describe.only('ABI Encoder', () => {
                 someUint32: new BigNumber(30472),
                 nestedTuple: {
                     someUint: new BigNumber('48384725243211555532'),
-                    someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
-                }
+                    someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
+                },
             };
             const secondTuple = {
                 someUint: new BigNumber(2984237422),
@@ -640,50 +587,47 @@ describe.only('ABI Encoder', () => {
                         someUint: new BigNumber(234324),
                         someStr: 'Im also a short string -- oops I just got loooooooooooooooooonger!',
                         someBytes: '0x23847287fff3472984723498ff23487324987aaa237438911873429472ba',
-                        someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498'
-                    }
+                        someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
+                    },
                 },
                 someBytes: '0x2834y3947289423u489aaaff4783924739847489',
                 someAddress: '0xe41d2489571d322189246dafa5ebde1f4699afaf',
             };
             const thirdTuple = {
-                'someUint': new BigNumber(37422),
-                'someStr': 'This into the next word of memory. string will exceed 256 bits, so it will spill.',
-                'nestedTuple': {
+                someUint: new BigNumber(37422),
+                someStr: 'This into the next word of memory. string will exceed 256 bits, so it will spill.',
+                nestedTuple: {
                     someUint32: new BigNumber(23999222),
-                    'secondNestedTuple': {
-                        'someUint': new BigNumber(324),
-                        'someStr': 'Im also a short st',
-                        'someBytes': '0x723498ff2348732498723847287fff3472984aaa237438911873429472ba',
-                        'someAddress': '0x46dafa5ebde1f4699f498e41d2489571d3221892'
-                    }
+                    secondNestedTuple: {
+                        someUint: new BigNumber(324),
+                        someStr: 'Im also a short st',
+                        someBytes: '0x723498ff2348732498723847287fff3472984aaa237438911873429472ba',
+                        someAddress: '0x46dafa5ebde1f4699f498e41d2489571d3221892',
+                    },
                 },
-                'someBytes': '0x947289423u489aaaff472834y383924739847489',
-                'someAddress': '0x46dafa5ebde1f46e41d2489571d322189299afaf',
+                someBytes: '0x947289423u489aaaff472834y383924739847489',
+                someAddress: '0x46dafa5ebde1f46e41d2489571d322189299afaf',
             };
             const fourthTuple = {
-                'someUint': new BigNumber(222283488822),
-                'someStr': 'exceed 256 bits, so it will spill into the. This string will next word of memory.',
-                'nestedTuple': {
+                someUint: new BigNumber(222283488822),
+                someStr: 'exceed 256 bits, so it will spill into the. This string will next word of memory.',
+                nestedTuple: {
                     someUint32: new BigNumber(2300),
-                    'secondNestedTuple': {
-                        'someUint': new BigNumber(343224),
-                        'someStr': 'The alphabet backwards is arguably easier to say if thats the way you learned the first time.',
-                        'someBytes': '0x87324987aaa23743891187323847287fff3472984723498ff234429472ba',
-                        'someAddress': '0x71d322189246dafa5ebe41d24895de1f4699f498'
-                    }
+                    secondNestedTuple: {
+                        someUint: new BigNumber(343224),
+                        someStr:
+                            'The alphabet backwards is arguably easier to say if thats the way you learned the first time.',
+                        someBytes: '0x87324987aaa23743891187323847287fff3472984723498ff234429472ba',
+                        someAddress: '0x71d322189246dafa5ebe41d24895de1f4699f498',
+                    },
                 },
-                'someBytes': '0x2783924739847488343947289423u489aaaff490',
-                'someAddress': '0xebde1d322189246dafa1f4699afafe41d2489575',
+                someBytes: '0x2783924739847488343947289423u489aaaff490',
+                someAddress: '0xebde1d322189246dafa1f4699afafe41d2489575',
             };
-            const args = [
-                [firstTuple],
-                [secondTuple, thirdTuple, fourthTuple]
-            ];
+            const args = [[firstTuple], [secondTuple, thirdTuple, fourthTuple]];
 
             console.log('*'.repeat(250), method, '*'.repeat(250));
 
-
             const calldata = method.encode(args);
             console.log(method.getSignature());
             console.log(method.selector);
@@ -693,37 +637,9 @@ describe.only('ABI Encoder', () => {
             const expectedCalldata = '0x';
             expect(calldata).to.be.equal(expectedCalldata);
         });
-
-        it.skip('Object ABI (Object input - Missing Key)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([{ someUint: new BigNumber(5) }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-
-            // @TODO: Figure out how to catch throw
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
-
-        it.skip('Object ABI (Object input - Too Many Keys)', async () => {
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const calldata = method.encode([{ someUint: new BigNumber(5), someStr: 'five', unwantedKey: 14 }]);
-            console.log(method.getSignature());
-            console.log(method.selector);
-
-            console.log(calldata);
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-
-            // @TODO: Figure out how to catch throw
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
     });
 
-    describe.only('Array', () => {
+    describe('Array', () => {
         it('Fixed size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[2]' };
@@ -732,7 +648,8 @@ describe.only('ABI Encoder', () => {
             const args = [new BigNumber(5), new BigNumber(6)];
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -740,7 +657,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Dynamic size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[]' };
@@ -749,7 +665,8 @@ describe.only('ABI Encoder', () => {
             const args = [new BigNumber(5), new BigNumber(6)];
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -757,16 +674,16 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Fixed size; Dynamic elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[2]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
             // Construct args to be encoded
-            const args = ["Hello", "world"];
+            const args = ['Hello', 'world'];
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -774,16 +691,16 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Dynamic size; Dynamic elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[]' };
             const dataType = new AbiEncoder.SolArray(testDataItem);
             // Construct args to be encoded
-            const args = ["Hello", "world"];
+            const args = ['Hello', 'world'];
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -791,21 +708,56 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
-        // @TODO: Add test that fails if we pass in the wrong number of elements
-        // @TODO: Add test that fails if we pass in an element of incorrecrt type
+        it('Static size; Too Few Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[3]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const args = ['Hello', 'world'];
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Expected array of 3 elements, but got array of length 2');
+        });
+        it('Static size; Too Many Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[1]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const args = ['Hello', 'world'];
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Expected array of 1 elements, but got array of length 2');
+        });
+        it('Element Type Mismatch', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'uint[]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const args = [new BigNumber(1), 'Bad Argument'];
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
     });
 
-    describe.only('Tuple', () => {
+    describe('Tuple', () => {
         it('Static elements only', async () => {
             // Create DataType object
-            const testDataItem = { name: 'Tuple', type: 'tuple', components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }] };
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
+            };
             const dataType = new AbiEncoder.Tuple(testDataItem);
             // Construct args to be encoded
             const args = { field_1: new BigNumber(-5), field_2: true };
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
+            const expectedEncodedArgs =
+                '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodingRules = { structsAsObjects: true } as DecodingRules;
@@ -814,16 +766,20 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Dynamic elements only', async () => {
             // Create DataType object
-            const testDataItem = { name: 'Tuple', type: 'tuple', components: [{ name: 'field_1', type: 'string' }, { name: 'field_2', type: 'bytes' }] };
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'string' }, { name: 'field_2', type: 'bytes' }],
+            };
             const dataType = new AbiEncoder.Tuple(testDataItem);
             // Construct args to be encoded
-            const args = { field_1: "Hello, World!", field_2: '0xabcdef0123456789' };
+            const args = { field_1: 'Hello, World!', field_2: '0xabcdef0123456789' };
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodingRules = { structsAsObjects: true } as DecodingRules;
@@ -832,16 +788,30 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Static and dynamic elements mixed', async () => {
             // Create DataType object
-            const testDataItem = { name: 'Tuple', type: 'tuple', components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'string' }, { name: 'field_3', type: 'bool' }, { name: 'field_4', type: 'bytes' }] };
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [
+                    { name: 'field_1', type: 'int32' },
+                    { name: 'field_2', type: 'string' },
+                    { name: 'field_3', type: 'bool' },
+                    { name: 'field_4', type: 'bytes' },
+                ],
+            };
             const dataType = new AbiEncoder.Tuple(testDataItem);
             // Construct args to be encoded
-            const args = { field_1: new BigNumber(-5), field_2: "Hello, World!", field_3: true, field_4: '0xabcdef0123456789' };
+            const args = {
+                field_1: new BigNumber(-5),
+                field_2: 'Hello, World!',
+                field_3: true,
+                field_4: '0xabcdef0123456789',
+            };
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodingRules = { structsAsObjects: true } as DecodingRules;
@@ -850,12 +820,39 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
-        // @TODO: Add test that fails if we pass in the wrong number of elements
-        // @TODO: Add test that fails if we pass in arguments in wrong order
+        it('Missing Key', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: new BigNumber(-5) };
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Could not assign tuple to object: missing keys field_2');
+        });
+        it('Bad Key', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { unknown_field: new BigNumber(-5) };
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw("Could not assign tuple to object: unrecognized key 'unknown_field' in object Tuple");
+        });
     });
 
-    describe.only('Address', () => {
+    describe('Address', () => {
         it('Valid Address', async () => {
             // Create DataType object
             const testDataItem = { name: 'Address', type: 'address' };
@@ -872,7 +869,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Invalid Address - input is not valid hex', async () => {
             // Create DataType object
             const testDataItem = { name: 'Address', type: 'address' };
@@ -880,9 +876,10 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = 'e4';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
         });
-
         it('Invalid Address - input is not 20 bytes', async () => {
             // Create DataType object
             const testDataItem = { name: 'Address', type: 'address' };
@@ -890,11 +887,13 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '0xe4';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
         });
     });
 
-    describe.only('Bool', () => {
+    describe('Bool', () => {
         it('True', async () => {
             // Create DataType object
             const testDataItem = { name: 'Boolean', type: 'bool' };
@@ -911,7 +910,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('False', async () => {
             // Create DataType object
             const testDataItem = { name: 'Boolean', type: 'bool' };
@@ -930,7 +928,7 @@ describe.only('ABI Encoder', () => {
         });
     });
 
-    describe.only('Integer', () => {
+    describe('Integer', () => {
         it('Int256 - Positive Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
@@ -947,7 +945,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int256 - Negative Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
@@ -964,13 +961,12 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int256 - Positive Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max256BitInteger = (new BigNumber(2)).pow(255).minus(1);
+            const max256BitInteger = new BigNumber(2).pow(255).minus(1);
             const args = max256BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -982,13 +978,12 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int256 - Negative Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min256BitInteger = (new BigNumber(2)).pow(255).times(-1);
+            const min256BitInteger = new BigNumber(2).pow(255).times(-1);
             const args = min256BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1000,29 +995,30 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int256 - Value too large', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max256BitInteger = (new BigNumber(2)).pow(255).minus(1);
+            const max256BitInteger = new BigNumber(2).pow(255).minus(1);
             const args = max256BitInteger.plus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
-
         it('Int256 - Value too small', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min256BitInteger = (new BigNumber(2)).pow(255).times(-1);
+            const min256BitInteger = new BigNumber(2).pow(255).times(-1);
             const args = min256BitInteger.minus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
-
         it('Int32 - Positive Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
@@ -1039,7 +1035,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int32 - Negative Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
@@ -1056,13 +1051,12 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int32 - Positive Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max32BitInteger = (new BigNumber(2)).pow(31).minus(1);
+            const max32BitInteger = new BigNumber(2).pow(31).minus(1);
             const args = max32BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1074,13 +1068,12 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int32 - Negative Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min32BitInteger = (new BigNumber(2)).pow(31).times(-1);
+            const min32BitInteger = new BigNumber(2).pow(31).times(-1);
             const args = min32BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1092,31 +1085,33 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Int32 - Value too large', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max32BitInteger = (new BigNumber(2)).pow(31).minus(1);
+            const max32BitInteger = new BigNumber(2).pow(31).minus(1);
             const args = max32BitInteger.plus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
-
         it('Int32 - Value too small', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min32BitInteger = (new BigNumber(2)).pow(31).times(-1);
+            const min32BitInteger = new BigNumber(2).pow(31).times(-1);
             const args = min32BitInteger.minus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
     });
 
-    describe.only('Unsigned Integer', () => {
+    describe('Unsigned Integer', () => {
         it('UInt256 - Positive Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
@@ -1133,13 +1128,12 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('UInt256 - Positive Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max256BitUnsignedInteger = (new BigNumber(2)).pow(256).minus(1);
+            const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
             const args = max256BitUnsignedInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1151,7 +1145,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('UInt256 - Zero Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
@@ -1169,29 +1162,30 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('UInt256 - Value too large', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max256BitUnsignedInteger = (new BigNumber(2)).pow(256).minus(1);
+            const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
             const args = max256BitUnsignedInteger.plus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
-
         it('UInt256 - Value too small', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const min256BitUnsignedInteger = new BigNumber(0)
+            const min256BitUnsignedInteger = new BigNumber(0);
             const args = min256BitUnsignedInteger.minus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
-
         it('UInt32 - Positive Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
@@ -1208,13 +1202,12 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('UInt32 - Positive Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max32BitUnsignedInteger = (new BigNumber(2)).pow(32).minus(1);
+            const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
             const args = max32BitUnsignedInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1226,7 +1219,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('UInt32 - Zero Value', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
@@ -1244,18 +1236,18 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('UInt32 - Value too large', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max32BitUnsignedInteger = (new BigNumber(2)).pow(32).minus(1);
+            const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
             const args = max32BitUnsignedInteger.plus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
-
         it('UInt32 - Value too small', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
@@ -1264,11 +1256,13 @@ describe.only('ABI Encoder', () => {
             const min32BitUnsignedInteger = new BigNumber(0);
             const args = min32BitUnsignedInteger.minus(1);
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw();
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
         });
     });
 
-    describe.only('Static Bytes', () => {
+    describe('Static Bytes', () => {
         it('Single Byte (byte)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Byte', type: 'byte' };
@@ -1285,7 +1279,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Single Byte (bytes1)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes1', type: 'bytes1' };
@@ -1302,7 +1295,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('4 Bytes (bytes4)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
@@ -1319,7 +1311,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('4 Bytes (bytes4); Encoder must pad input', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
@@ -1338,7 +1329,6 @@ describe.only('ABI Encoder', () => {
             const paddedArgsAsJson = JSON.stringify(paddedArgs);
             expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
         });
-
         it('32 Bytes (bytes32)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
@@ -1355,7 +1345,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('32 Bytes (bytes32); Encoder must pad input', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
@@ -1374,7 +1363,6 @@ describe.only('ABI Encoder', () => {
             const paddedArgsAsJson = JSON.stringify(paddedArgs);
             expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
         });
-
         it('Should throw when pass in too many bytes (bytes4)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
@@ -1382,9 +1370,12 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '0x0102030405';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x0102030405 (5 bytes), which exceeds max bytes that can be stored in a bytes4');
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(
+                'Tried to assign 0x0102030405 (5 bytes), which exceeds max bytes that can be stored in a bytes4',
+            );
         });
-
         it('Should throw when pass in too many bytes (bytes32)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
@@ -1392,9 +1383,12 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '0x010203040506070809101112131415161718192021222324252627282930313233';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x010203040506070809101112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32');
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(
+                'Tried to assign 0x010203040506070809101112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32',
+            );
         });
-
         it('Should throw when pass in bad hex (no 0x prefix)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
@@ -1402,9 +1396,10 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '0102030405060708091011121314151617181920212223242526272829303132';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
         });
-
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
@@ -1412,11 +1407,13 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '0x010';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
         });
     });
 
-    describe.only('Dynamic Bytes Dynamic', () => {
+    describe('Dynamic Bytes', () => {
         it('Fits into one EVM word', async () => {
             // Create DataType object
             const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
@@ -1426,7 +1423,8 @@ describe.only('ABI Encoder', () => {
             const args = '0x1a18bf61';
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -1434,7 +1432,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Spans multiple EVM words', async () => {
             // Create DataType object
             const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
@@ -1444,7 +1441,8 @@ describe.only('ABI Encoder', () => {
             const args = '0x' + '61'.repeat(40);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -1452,7 +1450,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Input as Buffer', async () => {
             // Create DataType object
             const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
@@ -1463,7 +1460,8 @@ describe.only('ABI Encoder', () => {
             const argsAsBuffer = ethUtil.toBuffer(args);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(argsAsBuffer);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -1471,7 +1469,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Should throw when pass in bad hex (no 0x prefix)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes', type: 'bytes' };
@@ -1479,9 +1476,10 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '01';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
         });
-
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes', type: 'bytes' };
@@ -1489,11 +1487,13 @@ describe.only('ABI Encoder', () => {
             // Construct args to be encoded
             const args = '0x010';
             // Encode Args and validate result
-            expect(() => { dataType.encode(args) }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
         });
     });
 
-    describe.only('String', () => {
+    describe('String', () => {
         it('Fits into one EVM word', async () => {
             // Create DataType object
             const testDataItem = { name: 'String', type: 'string' };
@@ -1503,7 +1503,8 @@ describe.only('ABI Encoder', () => {
             const args = 'five';
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -1511,7 +1512,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('Spans multiple EVM words', async () => {
             // Create DataType object
             const testDataItem = { name: 'String', type: 'string' };
@@ -1521,7 +1521,8 @@ describe.only('ABI Encoder', () => {
             const args = 'a'.repeat(40);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
@@ -1529,7 +1530,6 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
-
         it('String that begins with 0x prefix', async () => {
             // Create DataType object
             const testDataItem = { name: 'String', type: 'string' };
@@ -1539,7 +1539,8 @@ describe.only('ABI Encoder', () => {
             const args = '0x' + 'a'.repeat(40);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts
index aa38711cd..806ad1700 100644
--- a/packages/utils/test/abi_samples.ts
+++ b/packages/utils/test/abi_samples.ts
@@ -34,32 +34,32 @@ export const stringAbi = {
     type: 'function',
 } as MethodAbi;
 
-
 export const GAbi = {
     constant: false,
     inputs: [
         {
-            components: [{
-                name: 'a',
-                type: 'uint256',
-            },
-            {
-                name: 'b',
-                type: 'string',
-            },
-            {
-                name: 'e',
-                type: 'bytes',
-            },
-            {
-                name: 'f',
-                type: 'address',
-            }],
+            components: [
+                {
+                    name: 'a',
+                    type: 'uint256',
+                },
+                {
+                    name: 'b',
+                    type: 'string',
+                },
+                {
+                    name: 'e',
+                    type: 'bytes',
+                },
+                {
+                    name: 'f',
+                    type: 'address',
+                },
+            ],
 
             name: 'f',
             type: 'tuple',
-
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -137,6 +137,25 @@ export const optimizerAbi4 = {
     type: 'function',
 } as MethodAbi;
 
+export const optimizerAbi5 = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'uint8[]',
+        },
+        {
+            name: 'array2',
+            type: 'uint8[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
 export const typesWithDefaultWidthsAbi = {
     constant: false,
     inputs: [
@@ -456,7 +475,7 @@ export const staticArrayAbi = {
         {
             name: 'someStaticArray',
             type: 'uint8[3]',
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -471,7 +490,7 @@ export const staticArrayDynamicMembersAbi = {
         {
             name: 'someStaticArray',
             type: 'string[3]',
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -486,7 +505,7 @@ export const dynamicArrayDynamicMembersAbi = {
         {
             name: 'someStaticArray',
             type: 'string[]',
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -501,7 +520,7 @@ export const dynamicArrayStaticMembersAbi = {
         {
             name: 'someStaticArray',
             type: 'uint8[]',
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -510,7 +529,7 @@ export const dynamicArrayStaticMembersAbi = {
     type: 'function',
 } as MethodAbi;
 
-export const crazyAbi1 = {
+export const largeFlatAbi = {
     constant: false,
     inputs: [
         {
@@ -557,7 +576,7 @@ export const crazyAbi1 = {
     type: 'function',
 } as MethodAbi;
 
-export const crazyAbi = {
+export const largeNestedAbi = {
     constant: false,
     inputs: [
         {
@@ -641,7 +660,7 @@ export const crazyAbi = {
                     type: 'address',
                 },
             ],
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
@@ -730,7 +749,7 @@ export const nestedTuples = {
                     type: 'address',
                 },
             ],
-        }
+        },
     ],
     name: 'simpleFunction',
     outputs: [],
-- 
cgit v1.2.3


From 0d65c9da4ad6d925779b9b6e8ff99bea4c25eedf Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 16:52:45 -0800
Subject: Optimizer Tests

---
 packages/utils/test/abi_encoder_test.ts | 272 +++++++++++++++++++++++---------
 packages/utils/test/abi_samples.ts      |  88 -----------
 2 files changed, 200 insertions(+), 160 deletions(-)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 9925abcc3..c5be35d5e 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -4,6 +4,7 @@ import 'mocha';
 import { chaiSetup } from './utils/chai_setup';
 import { BigNumber, AbiEncoder } from '../src/';
 import * as AbiSamples from './abi_samples';
+import * as OptimizedAbis from './optimizer_abis';
 import { DecodingRules } from '../src/abi_encoder';
 import ethUtil = require('ethereumjs-util');
 
@@ -12,19 +13,17 @@ const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
     describe('Optimizer', () => {
-        it('Should reuse duplicate strings in string array', async () => {
-            // Description:
-            //   There are two unique values in the array `strings`.
-            //   There should exist only one copy of each string in the optimized calldata.
-            //   In unoptimized calldata, two copies of each string will be created.
+        it('Duplicate Dynamic Arrays with Static Elements', async () => {
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
-            const strings = ['Test String', 'Test String 2', 'Test String', 'Test String 2'];
-            const args = [strings];
-            // Validate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
+            const array1 = [new BigNumber(100), new BigNumber(150)];
+            const array2 = array1;
+            const args = [array1, array2];
+            // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
+            console.log(optimizedCalldata);
             const expectedOptimizedCalldata =
-                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000';
+                '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
@@ -32,21 +31,68 @@ describe.only('ABI Encoder', () => {
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-        it('Should point array elements to a duplicate value from another parameter', async () => {
-            // Description:
-            //   There are two unique values in the array `strings`.
-            //   The value "Test String" appears three times in this array.
-            //   There should exist only one copy of this string in the optimized calldata.
-            //   In unoptimized calldata, "Test String" would be written three times.
+        it('Duplicate Dynamic Arrays with Dynamic Elements', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements);
+            const array1 = ["Hello", "World"];
+            const array2 = array1;
+            const args = [array1, array2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Static Arrays with Static Elements (should not optimize)', async () => {
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2);
-            const strings = ['Test String', 'Test String', 'Test String', 'Test String 2'];
-            const string = 'Test String';
-            const args = [strings, string];
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithStaticElements);
+            const array1 = [new BigNumber(100), new BigNumber(150)];
+            const array2 = array1;
+            const args = [array1, array2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x7f8130430000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            const unoptimizedCalldata = method.encode(args);
+            expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Static Arrays with Dynamic Elements', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements);
+            const array1 = ["Hello", "World"];
+            const array2 = array1;
+            const args = [array1, array2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Array Elements (should optimize)', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateArrayElements);
+            const strings = ['Hello', 'World', 'Hello', 'World'];
+            const args = [strings];
             // Validate calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata =
-                '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000';
+                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
@@ -54,24 +100,15 @@ describe.only('ABI Encoder', () => {
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-        it('Dynamic Array of uints should point to Dynamic Array of Tuple(Uint)s', async () => {
-            // Description:
-            //   There are two dynamic arrays, one of uint's and one of tuples.
-            //   Each tuple is simply a wrapper for a uint - tuple := {key: uintValue}
-            //   While the elements of these arrays have different types, they
-            //   have the same representation in calldata.
-            //   That is, a `uint` and a `tuple{uint}` both consume exactly one word of calldata.
-            //   In the optimized calldata, only the elements of one array should be included.
-            //   Both arrays will then point to the same set of elements.
+        it('Duplicate Tuple Fields', async () => {
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi3);
-            const uint8Array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
-            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
-            const args = [uint8Array, uintTupleArray];
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTupleFields);
+            const tuple = ['Hello', 'Hello'];
+            const args = [tuple];
             // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata =
-                '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
+                '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
@@ -79,20 +116,18 @@ describe.only('ABI Encoder', () => {
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-        it('Duplicate Dynamic Arrays', async () => {
+        it('Duplicate Strings', async () => {
             // Description:
             //   Two dynamic arrays with the same values.
             //   In the optimized calldata, only one set of elements should be included.
             //   Both arrays should point to this set.
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5);
-            const array1 = [new BigNumber(100), new BigNumber(150)];
-            const array2 = [array1[0], array1[1]];
-            const args = [array1, array2];
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateStrings);
+            const args = ['Hello', 'Hello'];
             // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata =
-                '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+                '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
@@ -100,22 +135,19 @@ describe.only('ABI Encoder', () => {
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-
-        /*
-        it.only('Duplicate Static Arrays', async () => {
+        it('Duplicate Bytes', async () => {
             // Description:
             //   Two dynamic arrays with the same values.
             //   In the optimized calldata, only one set of elements should be included.
             //   Both arrays should point to this set.
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5);
-            const array1 = [new BigNumber(100), new BigNumber(150)];
-            const array2 = [array1[0], array1[1]];
-            const args = [array1, array2];
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateBytes);
+            const value = '0x01020304050607080910111213141516171819202122232425262728293031323334353637383940';
+            const args = [value, value];
             // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata =
-                '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+                '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
@@ -123,49 +155,145 @@ describe.only('ABI Encoder', () => {
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-
-        it.only('Duplicate Tuples', async () => {
+        it('Duplicate Tuples', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
+            const tuple1 = ['Hello, World!', new BigNumber(424234)];
+            const tuple2 = tuple1;
+            const args = [tuple1, tuple2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Fields Across Two Tuples', async () => {
             // Description:
-            //   Two dynamic arrays with the same values.
-            //   In the optimized calldata, only one set of elements should be included.
-            //   Both arrays should point to this set.
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5);
-            const array1 = [new BigNumber(100), new BigNumber(150)];
-            const array2 = [array1[0], array1[1]];
-            const args = [array1, array2];
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
+            const tuple1 = ['Hello, World!', new BigNumber(1)];
+            const tuple2 = [tuple1[0], new BigNumber(2)];
+            const args = [tuple1, tuple2];
             // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata =
-                '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+                '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
-        });*/
-
-        it('Static Array of static types should not be optimized', async () => {
+        });
+        it('Duplicate Arrays, Nested in Separate Tuples', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateArraysNestedInTuples);
+            const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200)];
+            const tuple1 = [array];
+            const tuple2 = [array, 'extra argument to prevent exactly matching the tuples'];
+            const args = [tuple1, tuple2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Tuples, Nested in Separate Tuples', async () => {
             // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
-            const uint8Array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
-            const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]];
-            const args = [uint8Array, uintTupleArray];
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuplesNestedInTuples);
+            const nestedTuple = ['Hello, World!'];
+            const tuple1 = [nestedTuple];
+            const tuple2 = [nestedTuple, 'extra argument to prevent exactly matching the tuples'];
+            const args = [tuple1, tuple2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Two-Dimensional Arrays', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
+            const twoDimArray1 = [['Hello', 'World'], ['Foo', 'Bar', 'Zaa']];
+            const twoDimArray2 = twoDimArray1;
+            const args = [twoDimArray1, twoDimArray2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: false });
+            const expectedOptimizedCalldata =
+                '0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Duplicate Array, Nested within Separate Two-Dimensional Arrays', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
+            const twoDimArray1 = [['Hello', 'World'], ['Foo']];
+            const twoDimArray2 = [['Hello', 'World'], ['Bar']];
+            const args = [twoDimArray1, twoDimArray2];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Array Elements Duplicated as Tuple Fields', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsTupleFields);
+            const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
+            const tuple = [[array[0]], [array[1]], [array[2]], [array[3]]];
+            const args = [array, tuple];
+            // Validata calldata
+            const optimizedCalldata = method.encode(args, { optimize: true });
+            const expectedOptimizedCalldata =
+                '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+            // Validate decoding
+            const decodedArgs = method.decode(optimizedCalldata);
+            const decodedArgsJson = JSON.stringify(decodedArgs);
+            const argsJson = JSON.stringify(args);
+            expect(decodedArgsJson).to.be.equal(argsJson);
+        });
+        it('Array Elements Duplicated as Separate Parameter', async () => {
+            // Generate calldata
+            const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsSeparateParameter);
+            const array = ['Hello', 'Hello', 'Hello', 'World'];
+            const string = 'Hello';
+            const args = [array, string];
             // Validate calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
-            const unoptimizedCalldata = method.encode(args);
-            expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
+            const expectedOptimizedCalldata =
+                '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
             // Validate decoding
             const decodedArgs = method.decode(optimizedCalldata);
             const decodedArgsJson = JSON.stringify(decodedArgs);
             const argsJson = JSON.stringify(args);
             expect(decodedArgsJson).to.be.equal(argsJson);
         });
-
-        // Todo: Unfixed array points to fixed array
-        // Todo: Unfixed to unfixed array
-        // Todo: Duplicate tuples
     });
 
     describe('Method ABIs', () => {
diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts
index 806ad1700..0c3354044 100644
--- a/packages/utils/test/abi_samples.ts
+++ b/packages/utils/test/abi_samples.ts
@@ -68,94 +68,6 @@ export const GAbi = {
     type: 'function',
 } as MethodAbi;
 
-export const optimizerAbi2 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'stringArray',
-            type: 'string[]',
-        },
-        {
-            name: 'string',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const optimizerAbi3 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'uint8Array',
-            type: 'uint8[]',
-        },
-        {
-            components: [
-                {
-                    name: 'uint',
-                    type: 'uint',
-                },
-            ],
-            name: 'uintTuple',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const optimizerAbi4 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'uint8Array',
-            type: 'uint8[4]',
-        },
-        {
-            components: [
-                {
-                    name: 'uint',
-                    type: 'uint',
-                },
-            ],
-            name: 'uintTuple',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
-export const optimizerAbi5 = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array1',
-            type: 'uint8[]',
-        },
-        {
-            name: 'array2',
-            type: 'uint8[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-} as MethodAbi;
-
 export const typesWithDefaultWidthsAbi = {
     constant: false,
     inputs: [
-- 
cgit v1.2.3


From acd570b2b30b9ffcc2333291dead9ffd5d1bd62a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 17:31:32 -0800
Subject: Multidimensional Array tests

---
 packages/utils/test/abi_encoder_test.ts | 154 +++++++++++++++++---------------
 1 file changed, 80 insertions(+), 74 deletions(-)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index c5be35d5e..d75d1ae50 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -21,7 +21,6 @@ describe.only('ABI Encoder', () => {
             const args = [array1, array2];
             // Validata calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
-            console.log(optimizedCalldata);
             const expectedOptimizedCalldata =
                 '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
             expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -692,79 +691,6 @@ describe.only('ABI Encoder', () => {
             const decodedValueJson = JSON.stringify(decodedValue);
             expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
         });
-
-        // @TODO: Test Nested Tuples (Not Supported on )
-
-        it.skip('Nested Tuples', async () => {
-            // Couldn't get nested tuples to work with Remix
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.nestedTuples);
-            const firstTuple = {
-                someUint32: new BigNumber(30472),
-                nestedTuple: {
-                    someUint: new BigNumber('48384725243211555532'),
-                    someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
-                },
-            };
-            const secondTuple = {
-                someUint: new BigNumber(2984237422),
-                someStr: 'This string will exceed 256 bits, so it will spill into the next word of memory.',
-                nestedTuple: {
-                    someUint32: new BigNumber(23),
-                    secondNestedTuple: {
-                        someUint: new BigNumber(234324),
-                        someStr: 'Im also a short string -- oops I just got loooooooooooooooooonger!',
-                        someBytes: '0x23847287fff3472984723498ff23487324987aaa237438911873429472ba',
-                        someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
-                    },
-                },
-                someBytes: '0x2834y3947289423u489aaaff4783924739847489',
-                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699afaf',
-            };
-            const thirdTuple = {
-                someUint: new BigNumber(37422),
-                someStr: 'This into the next word of memory. string will exceed 256 bits, so it will spill.',
-                nestedTuple: {
-                    someUint32: new BigNumber(23999222),
-                    secondNestedTuple: {
-                        someUint: new BigNumber(324),
-                        someStr: 'Im also a short st',
-                        someBytes: '0x723498ff2348732498723847287fff3472984aaa237438911873429472ba',
-                        someAddress: '0x46dafa5ebde1f4699f498e41d2489571d3221892',
-                    },
-                },
-                someBytes: '0x947289423u489aaaff472834y383924739847489',
-                someAddress: '0x46dafa5ebde1f46e41d2489571d322189299afaf',
-            };
-            const fourthTuple = {
-                someUint: new BigNumber(222283488822),
-                someStr: 'exceed 256 bits, so it will spill into the. This string will next word of memory.',
-                nestedTuple: {
-                    someUint32: new BigNumber(2300),
-                    secondNestedTuple: {
-                        someUint: new BigNumber(343224),
-                        someStr:
-                            'The alphabet backwards is arguably easier to say if thats the way you learned the first time.',
-                        someBytes: '0x87324987aaa23743891187323847287fff3472984723498ff234429472ba',
-                        someAddress: '0x71d322189246dafa5ebe41d24895de1f4699f498',
-                    },
-                },
-                someBytes: '0x2783924739847488343947289423u489aaaff490',
-                someAddress: '0xebde1d322189246dafa1f4699afafe41d2489575',
-            };
-            const args = [[firstTuple], [secondTuple, thirdTuple, fourthTuple]];
-
-            console.log('*'.repeat(250), method, '*'.repeat(250));
-
-            const calldata = method.encode(args);
-            console.log(method.getSignature());
-            console.log(method.selector);
-            console.log(JSON.stringify(args));
-
-            console.log(calldata);
-            const expectedCalldata = '0x';
-            expect(calldata).to.be.equal(expectedCalldata);
-        });
     });
 
     describe('Array', () => {
@@ -836,6 +762,86 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
+        it('Dynamic Size; Multidimensional; Dynamic Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes[][]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617'];
+            const array3 = ['0x18192021'];
+            const args = [array1, array2, array3];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000041011121300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414151617000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Dynamic Size; Multidimensional; Static Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes4[][]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617'];
+            const array3 = ['0x18192021'];
+            const args = [array1, array2, array3];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000301020304000000000000000000000000000000000000000000000000000000000506070800000000000000000000000000000000000000000000000000000000091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021011121300000000000000000000000000000000000000000000000000000000141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Static Size; Multidimensional; Static Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes4[3][2]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617', '0x18192021'];
+            const args = [array1, array2];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x010203040000000000000000000000000000000000000000000000000000000005060708000000000000000000000000000000000000000000000000000000000910111200000000000000000000000000000000000000000000000000000000101112130000000000000000000000000000000000000000000000000000000014151617000000000000000000000000000000000000000000000000000000001819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Static Size; Multidimensional; Dynamic Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes[3][2]' };
+            const dataType = new AbiEncoder.SolArray(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617', '0x18192021'];
+            const args = [array1, array2];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            console.log(encodedArgs);
+            console.log(dataType.encode(args, { annotate: true }));
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000401020304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040910111200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000410111213000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
         it('Static size; Too Few Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[3]' };
-- 
cgit v1.2.3


From 6daa79ec12557c06a5d4d6876dd086d554addb24 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 17:43:30 -0800
Subject: Arrays nested in tuples

---
 packages/utils/test/abi_encoder_test.ts | 92 +++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index d75d1ae50..b672d0023 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -922,6 +922,98 @@ describe.only('ABI Encoder', () => {
             const argsAsJson = JSON.stringify(args);
             expect(decodedArgsAsJson).to.be.equal(argsAsJson);
         });
+        it('Nested Static Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'uint[2]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field: [new BigNumber(1), new BigNumber(2)] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Dynamic Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'uint[]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field: [new BigNumber(1), new BigNumber(2)] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Static Multidimensional Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'bytes4[2][2]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708'];
+            const array2 = ['0x09101112', '0x13141516'];
+            const args = { field: [array1, array2] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Dynamic Multidimensional Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'bytes[2][2]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708'];
+            const array2 = ['0x09101112', '0x13141516'];
+            const args = { field: [array1, array2] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
         it('Static and dynamic elements mixed', async () => {
             // Create DataType object
             const testDataItem = {
-- 
cgit v1.2.3


From b0ebc6fa14adc08c074bea4d275cc31504c95d55 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 19 Nov 2018 18:42:40 -0800
Subject: Tests for decoding return values + Ability to encode return values

---
 packages/utils/src/abi_encoder/evm_data_types.ts | 19 +++----
 packages/utils/test/abi_encoder_test.ts          | 69 ++++++++++++++++++++++++
 2 files changed, 79 insertions(+), 9 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 10e7b987b..b862e9396 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -276,7 +276,7 @@ export class Byte extends PayloadDataType {
         if (valueBuf.byteLength > this.width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                    valueBuf.byteLength
+                valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
@@ -475,6 +475,7 @@ export class Method extends MemberDataType {
     private methodSignature: string;
     private methodSelector: string;
     private returnDataTypes: DataType[];
+    private returnDataItem: DataItem;
 
     // TMP
     public selector: string;
@@ -484,6 +485,7 @@ export class Method extends MemberDataType {
         this.methodSignature = this.computeSignature();
         this.selector = this.methodSelector = this.computeSelector();
         this.returnDataTypes = [];
+        this.returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
         const dummy = new Byte({ type: 'byte', name: 'DUMMY' }); // @TODO TMP
         _.each(abi.outputs, (dataItem: DataItem) => {
             this.returnDataTypes.push(this.getFactory().create(dataItem, dummy));
@@ -518,20 +520,19 @@ export class Method extends MemberDataType {
         return value;
     }
 
-    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
-        //console.log('O'.repeat(100), '\n', returndata, '\n', this.returnDataTypes, 'P'.repeat(100));
+    public encodeReturnValues(value: any, rules?: EncodingRules): string {
+        const returnDataType = new Tuple(this.returnDataItem);
+        const returndata = returnDataType.encode(value, rules);
+        return returndata;
+    }
 
+    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
         const returnValues: any[] = [];
         const rules_ = rules ? rules : ({ structsAsObjects: false } as DecodingRules);
         const rawReturnData = new RawCalldata(returndata, false);
         _.each(this.returnDataTypes, (dataType: DataType) => {
             returnValues.push(dataType.generateValue(rawReturnData, rules_));
         });
-
-        //console.log('*'.repeat(40), '\n', JSON.stringify(returnValues), '\n', '*'.repeat(100));
-        /*if (returnValues.length === 1) {
-            return returnValues[0];
-        }*/
         return returnValues;
     }
 
@@ -547,7 +548,7 @@ export class Method extends MemberDataType {
 export class EvmDataTypeFactory implements DataTypeFactory {
     private static instance: DataTypeFactory;
 
-    private constructor() {}
+    private constructor() { }
 
     public static getInstance(): DataTypeFactory {
         if (!EvmDataTypeFactory.instance) {
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index b672d0023..0220984b0 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -5,6 +5,7 @@ import { chaiSetup } from './utils/chai_setup';
 import { BigNumber, AbiEncoder } from '../src/';
 import * as AbiSamples from './abi_samples';
 import * as OptimizedAbis from './optimizer_abis';
+import * as ReturnValueAbis from './return_value_abis';
 import { DecodingRules } from '../src/abi_encoder';
 import ethUtil = require('ethereumjs-util');
 
@@ -12,6 +13,74 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe.only('ABI Encoder', () => {
+    describe('Decode Return Values', () => {
+        it('No Return Value', async () => {
+            // Decode return value
+            const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
+            const returnValue = '0x';
+            const decodedReturnValue = method.decodeReturnValues(returnValue);
+            const expectedDecodedReturnValue: any[] = [];
+            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+            const expectedDecodedReturnValueJson = JSON.stringify(expectedDecodedReturnValue);
+            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        });
+        it('Single static return value', async () => {
+            // Generate Return Value
+            const method = new AbiEncoder.Method(ReturnValueAbis.singleStaticReturnValue);
+            const returnValue = ['0x01020304'];
+            const encodedReturnValue = method.encodeReturnValues(returnValue);
+            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+            // Validate decoded return value
+            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        });
+        it('Multiple static return values', async () => {
+            // Generate Return Value
+            const method = new AbiEncoder.Method(ReturnValueAbis.multipleStaticReturnValues);
+            const returnValue = ['0x01020304', '0x05060708'];
+            const encodedReturnValue = method.encodeReturnValues(returnValue);
+            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+            // Validate decoded return value
+            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        });
+        it('Single dynamic return value', async () => {
+            // Generate Return Value
+            const method = new AbiEncoder.Method(ReturnValueAbis.singleDynamicReturnValue);
+            const returnValue = ['0x01020304'];
+            const encodedReturnValue = method.encodeReturnValues(returnValue);
+            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+            // Validate decoded return value
+            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        });
+        it('Multiple dynamic return values', async () => {
+            // Generate Return Value
+            const method = new AbiEncoder.Method(ReturnValueAbis.multipleDynamicReturnValues);
+            const returnValue = ['0x01020304', '0x05060708'];
+            const encodedReturnValue = method.encodeReturnValues(returnValue);
+            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+            // Validate decoded return value
+            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        });
+        it('Mixed static/dynamic return values', async () => {
+            // Generate Return Value
+            const method = new AbiEncoder.Method(ReturnValueAbis.mixedStaticAndDynamicReturnValues);
+            const returnValue = ['0x01020304', '0x05060708'];
+            const encodedReturnValue = method.encodeReturnValues(returnValue);
+            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+            // Validate decoded return value
+            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        });
+    });
+
     describe('Optimizer', () => {
         it('Duplicate Dynamic Arrays with Static Elements', async () => {
             // Generate calldata
-- 
cgit v1.2.3


From 2164b34bf9ca6f38fff93a527ee162b0624b818e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 10:07:57 -0800
Subject: Ran linter on Calldata

---
 packages/utils/src/abi_encoder/calldata.ts  | 505 +++++++++++++---------------
 packages/utils/src/abi_encoder/data_type.ts |  11 +-
 2 files changed, 241 insertions(+), 275 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index e6ce58957..9f91f8495 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -1,6 +1,6 @@
 import ethUtil = require('ethereumjs-util');
-import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
-var _ = require('lodash');
+const _ = require('lodash');
+import * as Constants from './constants';
 
 export interface DecodingRules {
     structsAsObjects: boolean;
@@ -12,77 +12,69 @@ export interface EncodingRules {
 }
 
 export abstract class CalldataBlock {
-    private name: string;
-    private signature: string;
-    private offsetInBytes: number;
-    private headerSizeInBytes: number;
-    private bodySizeInBytes: number;
-    private relocatable: boolean;
-    private parentName: string;
+    private readonly _signature: string;
+    private readonly _parentName: string;
+    private _name: string;
+    private _offsetInBytes: number;
+    private _headerSizeInBytes: number;
+    private _bodySizeInBytes: number;
 
     constructor(
         name: string,
         signature: string,
         parentName: string,
-        /*offsetInBytes: number,*/ headerSizeInBytes: number,
+        headerSizeInBytes: number,
         bodySizeInBytes: number,
-        relocatable: boolean,
     ) {
-        this.name = name;
-        this.signature = signature;
-        this.parentName = parentName;
-        this.offsetInBytes = 0;
-        this.headerSizeInBytes = headerSizeInBytes;
-        this.bodySizeInBytes = bodySizeInBytes;
-        this.relocatable = relocatable;
+        this._name = name;
+        this._signature = signature;
+        this._parentName = parentName;
+        this._offsetInBytes = 0;
+        this._headerSizeInBytes = headerSizeInBytes;
+        this._bodySizeInBytes = bodySizeInBytes;
     }
 
-    protected setHeaderSize(headerSizeInBytes: number) {
-        this.headerSizeInBytes = headerSizeInBytes;
+    protected _setHeaderSize(headerSizeInBytes: number): void {
+        this._headerSizeInBytes = headerSizeInBytes;
     }
 
-    protected setBodySize(bodySizeInBytes: number) {
-        this.bodySizeInBytes = bodySizeInBytes;
+    protected _setBodySize(bodySizeInBytes: number): void {
+        this._bodySizeInBytes = bodySizeInBytes;
     }
 
-    protected setName(name: string) {
-        this.name = name;
+    protected _setName(name: string): void {
+        this._name = name;
     }
 
     public getName(): string {
-        return this.name;
+        return this._name;
     }
 
     public getParentName(): string {
-        return this.parentName;
+        return this._parentName;
     }
 
     public getSignature(): string {
-        return this.signature;
+        return this._signature;
     }
-
-    public isRelocatable(): boolean {
-        return this.relocatable;
-    }
-
     public getHeaderSizeInBytes(): number {
-        return this.headerSizeInBytes;
+        return this._headerSizeInBytes;
     }
 
     public getBodySizeInBytes(): number {
-        return this.bodySizeInBytes;
+        return this._bodySizeInBytes;
     }
 
     public getSizeInBytes(): number {
-        return this.headerSizeInBytes + this.bodySizeInBytes;
+        return this.getHeaderSizeInBytes() + this.getBodySizeInBytes();
     }
 
     public getOffsetInBytes(): number {
-        return this.offsetInBytes;
+        return this._offsetInBytes;
     }
 
-    public setOffset(offsetInBytes: number) {
-        this.offsetInBytes = offsetInBytes;
+    public setOffset(offsetInBytes: number): void {
+        this._offsetInBytes = offsetInBytes;
     }
 
     public computeHash(): Buffer {
@@ -96,81 +88,80 @@ export abstract class CalldataBlock {
 }
 
 export class PayloadCalldataBlock extends CalldataBlock {
-    private payload: Buffer;
+    private readonly _payload: Buffer;
 
     constructor(
         name: string,
         signature: string,
         parentName: string,
-        /*offsetInBytes: number,*/ relocatable: boolean,
         payload: Buffer,
     ) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = payload.byteLength;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
-        this.payload = payload;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
+        this._payload = payload;
     }
 
     public toBuffer(): Buffer {
-        return this.payload;
+        return this._payload;
     }
 
     public getRawData(): Buffer {
-        return this.payload;
+        return this._payload;
     }
 }
 
 export class DependentCalldataBlock extends CalldataBlock {
-    public static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    public static RAW_DATA_START = new Buffer('<');
-    public static RAW_DATA_END = new Buffer('>');
-    private parent: CalldataBlock;
-    private dependency: CalldataBlock;
-    private aliasFor: CalldataBlock | undefined;
+    public static readonly RAW_DATA_START = new Buffer('<');
+    public static readonly RAW_DATA_END = new Buffer('>');
+    private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private static readonly _EMPTY_HEADER_SIZE = 0;
+    private readonly _parent: CalldataBlock;
+    private readonly _dependency: CalldataBlock;
+    private _aliasFor: CalldataBlock | undefined;
 
     constructor(
         name: string,
         signature: string,
         parentName: string,
-        relocatable: boolean,
         dependency: CalldataBlock,
         parent: CalldataBlock,
     ) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = DependentCalldataBlock.DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes, relocatable);
-        this.parent = parent;
-        this.dependency = dependency;
-        this.aliasFor = undefined;
+        const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE;
+        const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
+        this._parent = parent;
+        this._dependency = dependency;
+        this._aliasFor = undefined;
     }
 
     public toBuffer(): Buffer {
         const destinationOffset =
-            this.aliasFor !== undefined ? this.aliasFor.getOffsetInBytes() : this.dependency.getOffsetInBytes();
-        const parentOffset = this.parent.getOffsetInBytes();
-        const parentHeaderSize = this.parent.getHeaderSizeInBytes();
+            this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
+        const parentOffset = this._parent.getOffsetInBytes();
+        const parentHeaderSize = this._parent.getHeaderSizeInBytes();
         const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
-        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(16)}`);
+        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`);
         const evmWordWidthInBytes = 32;
         const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
         return pointerBufPadded;
     }
 
     public getDependency(): CalldataBlock {
-        return this.dependency;
+        return this._dependency;
     }
 
-    public setAlias(block: CalldataBlock) {
-        this.aliasFor = block;
-        this.setName(`${this.getName()} (alias for ${block.getName()})`);
+    public setAlias(block: CalldataBlock): void {
+        this._aliasFor = block;
+        this._setName(`${this.getName()} (alias for ${block.getName()})`);
     }
 
     public getAlias(): CalldataBlock | undefined {
-        return this.aliasFor;
+        return this._aliasFor;
     }
 
     public getRawData(): Buffer {
-        const dependencyRawData = this.dependency.getRawData();
+        const dependencyRawData = this._dependency.getRawData();
         const rawDataComponents: Buffer[] = [];
         rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
         rawDataComponents.push(dependencyRawData);
@@ -181,24 +172,21 @@ export class DependentCalldataBlock extends CalldataBlock {
 }
 
 export class MemberCalldataBlock extends CalldataBlock {
-    private static DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    private header: Buffer | undefined;
-    private members: CalldataBlock[];
-    private contiguous: boolean;
+    private _header: Buffer | undefined;
+    private _members: CalldataBlock[];
 
-    constructor(name: string, signature: string, parentName: string, relocatable: boolean, contiguous: boolean) {
-        super(name, signature, parentName, 0, 0, relocatable);
-        this.members = [];
-        this.header = undefined;
-        this.contiguous = contiguous;
+    constructor(name: string, signature: string, parentName: string) {
+        super(name, signature, parentName, 0, 0);
+        this._members = [];
+        this._header = undefined;
     }
 
     public getRawData(): Buffer {
         const rawDataComponents: Buffer[] = [];
-        if (this.header !== undefined) {
-            rawDataComponents.push(this.header);
+        if (this._header !== undefined) {
+            rawDataComponents.push(this._header);
         }
-        _.each(this.members, (member: CalldataBlock) => {
+        _.each(this._members, (member: CalldataBlock) => {
             const memberBuffer = member.getRawData();
             rawDataComponents.push(memberBuffer);
         });
@@ -207,91 +195,79 @@ export class MemberCalldataBlock extends CalldataBlock {
         return rawData;
     }
 
-    public setMembers(members: CalldataBlock[]) {
-        let bodySizeInBytes = 0;
-        _.each(members, (member: CalldataBlock) => {
-            bodySizeInBytes += member.getSizeInBytes();
-        });
-        this.members = members;
-        this.setBodySize(0);
-    }
-
-    public isContiguous(): boolean {
-        return true;
+    public setMembers(members: CalldataBlock[]): void {
+        this._members = members;
     }
 
-    public setHeader(header: Buffer) {
-        this.setHeaderSize(header.byteLength);
-        this.header = header;
+    public setHeader(header: Buffer): void {
+        this._setHeaderSize(header.byteLength);
+        this._header = header;
     }
 
     public toBuffer(): Buffer {
-        if (this.header !== undefined) return this.header;
+        if (this._header !== undefined) {
+            return this._header;
+        }
         return new Buffer('');
     }
 
     public getMembers(): CalldataBlock[] {
-        return this.members;
+        return this._members;
     }
 }
 
 class Queue<T> {
-    private store: T[] = [];
-    push(val: T) {
-        this.store.push(val);
+    private _store: T[] = [];
+    public push(val: T): void {
+        this._store.push(val);
     }
-    pushFront(val: T) {
-        this.store.unshift(val);
+    public pushFront(val: T): void {
+        this._store.unshift(val);
     }
-    pop(): T | undefined {
-        return this.store.shift();
+    public pop(): T | undefined {
+        return this._store.shift();
     }
-    popBack(): T | undefined {
-        if (this.store.length === 0) return undefined;
-        const backElement = this.store.splice(-1, 1)[0];
+    public popBack(): T | undefined {
+        if (this._store.length === 0) {
+            return undefined;
+        }
+        const backElement = this._store.splice(-1, 1)[0];
         return backElement;
     }
-    merge(q: Queue<T>) {
-        this.store = this.store.concat(q.store);
+    public merge(q: Queue<T>): void {
+        this._store = this._store.concat(q._store);
     }
-    mergeFront(q: Queue<T>) {
-        this.store = q.store.concat(this.store);
+    public mergeFront(q: Queue<T>): void {
+        this._store = q._store.concat(this._store);
     }
-    getStore(): T[] {
-        return this.store;
+    public getStore(): T[] {
+        return this._store;
     }
-    peek(): T | undefined {
-        return this.store.length >= 0 ? this.store[0] : undefined;
+    public peek(): T | undefined {
+        return this._store.length >= 0 ? this._store[0] : undefined;
     }
 }
 
 export class Calldata {
-    private selector: string;
-    private rules: EncodingRules;
-    private sizeInBytes: number;
-    private root: CalldataBlock | undefined;
-
-    constructor(rules: EncodingRules) {
-        this.selector = '';
-        this.rules = rules;
-        this.sizeInBytes = 0;
-        this.root = undefined;
-    }
+    private readonly _rules: EncodingRules;
+    private _selector: string;
+    private _sizeInBytes: number;
+    private _root: CalldataBlock | undefined;
 
-    private createQueue(block: CalldataBlock): Queue<CalldataBlock> {
+    private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
         const blockQueue = new Queue<CalldataBlock>();
 
         // Base Case
-        if (block instanceof MemberCalldataBlock === false) {
+        if (!(block instanceof MemberCalldataBlock)) {
             blockQueue.push(block);
             return blockQueue;
         }
 
         // This is a Member Block
-        const memberBlock = block as MemberCalldataBlock;
+        const memberBlock = block;
         _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
             if (member instanceof MemberCalldataBlock) {
-                blockQueue.mergeFront(this.createQueue(member));
+                blockQueue.mergeFront(Calldata._createQueue(member));
             } else {
                 blockQueue.pushFront(member);
             }
@@ -300,9 +276,9 @@ export class Calldata {
         // Children
         _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
             if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
-                let dependency = member.getDependency();
+                const dependency = member.getDependency();
                 if (dependency instanceof MemberCalldataBlock) {
-                    blockQueue.merge(this.createQueue(dependency));
+                    blockQueue.merge(Calldata._createQueue(dependency));
                 } else {
                     blockQueue.push(dependency);
                 }
@@ -313,91 +289,15 @@ export class Calldata {
         return blockQueue;
     }
 
-    private generateAnnotatedHexString(): string {
-        let hexValue = `${this.selector}`;
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = this.createQueue(this.root);
-
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        const functionBlock = valueQueue.peek();
-        let functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
-        while ((block = valueQueue.pop()) !== undefined) {
-            // Set f
-
-            // Process each block 1 word at a time
-            const size = block.getSizeInBytes();
-            const name = block.getName();
-            const parentName = block.getParentName();
-
-            //const ancestrialNamesOffset = name.startsWith('ptr<') ? 4 : 0;
-            //const parentOffset = name.lastIndexOf(parentName);
-            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, ''); //.replace(`${parentName}[`, '[');
-            const signature = block.getSignature();
-
-            // Current offset
-            let offsetStr = '';
-
-            // If this block is empty then it's a newline
-            let value = '';
-            let nameStr = '';
-            let line = '';
-            if (size === 0) {
-                offsetStr = ' '.repeat(10);
-                value = ' '.repeat(74);
-                nameStr = `### ${prettyName.padEnd(80)}`;
-                line = `\n${offsetStr}${value}${nameStr}`;
-            } else {
-                offsetStr = `0x${offset.toString(16)}`.padEnd(10, ' ');
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(0, 32))).padEnd(74);
-                if (block instanceof MemberCalldataBlock) {
-                    nameStr = `### ${prettyName.padEnd(80)}`;
-                    line = `\n${offsetStr}${value}${nameStr}`;
-                } else {
-                    nameStr = `    ${prettyName.padEnd(80)}`;
-                    line = `${offsetStr}${value}${nameStr}`;
-                }
-            }
-
-            for (let j = 32; j < size; j += 32) {
-                offsetStr = `0x${(offset + j).toString(16)}`.padEnd(10, ' ');
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + 32))).padEnd(74);
-                nameStr = ' '.repeat(40);
-
-                line = `${line}\n${offsetStr}${value}${nameStr}`;
-            }
-
-            // Append to hex value
-            hexValue = `${hexValue}\n${line}`;
-            offset += size;
-        }
-
-        return hexValue;
-    }
-
-    private generateCondensedHexString(): string {
-        let selectorBuffer = ethUtil.toBuffer(this.selector);
-        if (this.root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = this.createQueue(this.root);
-        const valueBufs: Buffer[] = [selectorBuffer];
-        let block: CalldataBlock | undefined;
-        while ((block = valueQueue.pop()) !== undefined) {
-            valueBufs.push(block.toBuffer());
-        }
-
-        const combinedBuffers = Buffer.concat(valueBufs);
-        const hexValue = ethUtil.bufferToHex(combinedBuffers);
-        return hexValue;
+    public constructor(rules: EncodingRules) {
+        this._rules = rules;
+        this._selector = '';
+        this._sizeInBytes = 0;
+        this._root = undefined;
     }
 
-    public optimize() {
-        if (this.root === undefined) {
+    public optimize(): void {
+        if (this._root === undefined) {
             throw new Error('expected root');
         }
 
@@ -405,14 +305,14 @@ export class Calldata {
 
         // 1. Create a queue of subtrees by hash
         // Note that they are ordered the same as
-        const subtreeQueue = this.createQueue(this.root);
+        const subtreeQueue = Calldata._createQueue(this._root);
         let block: CalldataBlock | undefined;
-        while ((block = subtreeQueue.popBack()) !== undefined) {
+        for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) {
             if (block instanceof DependentCalldataBlock) {
-                const blockHashBuf = block.getDependency().computeHash();
-                const blockHash = ethUtil.bufferToHex(blockHashBuf);
-                if (blockHash in blocksByHash) {
-                    const blockWithSameHash = blocksByHash[blockHash];
+                const dependencyBlockHashBuf = block.getDependency().computeHash();
+                const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
+                if (dependencyBlockHash in blocksByHash) {
+                    const blockWithSameHash = blocksByHash[dependencyBlockHash];
                     if (blockWithSameHash !== block.getDependency()) {
                         block.setAlias(blockWithSameHash);
                     }
@@ -422,69 +322,142 @@ export class Calldata {
 
             const blockHashBuf = block.computeHash();
             const blockHash = ethUtil.bufferToHex(blockHashBuf);
-            if (blockHash in blocksByHash === false) {
+            if (!(blockHash in blocksByHash)) {
                 blocksByHash[blockHash] = block;
             }
         }
     }
 
     public toHexString(): string {
-        if (this.root === undefined) {
+        if (this._root === undefined) {
             throw new Error('expected root');
         }
 
-        if (this.rules.optimize) this.optimize();
+        if (this._rules.optimize) {
+            this.optimize();
+        }
 
-        const offsetQueue = this.createQueue(this.root);
+        const offsetQueue = Calldata._createQueue(this._root);
         let block: CalldataBlock | undefined;
         let offset = 0;
-        while ((block = offsetQueue.pop()) !== undefined) {
+        for (block = offsetQueue.pop(); block !== undefined; block = offsetQueue.pop()) {
             block.setOffset(offset);
             offset += block.getSizeInBytes();
         }
 
-        const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
+        const hexValue = this._rules.annotate ? this._generateAnnotatedHexString() : this._generateCondensedHexString();
         return hexValue;
     }
 
     public getSelectorHex(): string {
-        return this.selector;
+        return this._selector;
     }
 
     public getSizeInBytes(): number {
-        return this.sizeInBytes;
+        return this._sizeInBytes;
     }
 
-    public toAnnotatedString(): string {
-        return '';
+    public setRoot(block: CalldataBlock): void {
+        this._root = block;
+        this._sizeInBytes += block.getSizeInBytes();
     }
 
-    public setRoot(block: CalldataBlock) {
-        this.root = block;
-        this.sizeInBytes += block.getSizeInBytes();
+    public setSelector(selector: string): void {
+        this._selector = selector.startsWith('0x') ? selector : `$0x${selector}`;
+        if (this._selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
+            throw new Error(`Invalid selector '${this._selector}'`);
+        }
+        this._sizeInBytes += Constants.HEX_SELECTOR_LENGTH_IN_BYTES; // @TODO: Used to be += 8. Bad?
     }
 
-    public setSelector(selector: string) {
-        // Ensure we have a 0x prefix
-        if (selector.startsWith('0x')) {
-            this.selector = selector;
-        } else {
-            this.selector = `$0x${selector}`;
+    private _generateAnnotatedHexString(): string {
+        let hexValue = `${this._selector}`;
+        if (this._root === undefined) {
+            throw new Error('expected root');
         }
 
-        // The selector must be 10 characters: '0x' followed by 4 bytes (two hex chars per byte)
-        if (this.selector.length !== 10) {
-            throw new Error(`Invalid selector '${this.selector}'`);
+        const valueQueue = Calldata._createQueue(this._root);
+
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        const functionBlock = valueQueue.peek();
+        const functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
+        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
+            // Process each block 1 word at a time
+            const size = block.getSizeInBytes();
+            const name = block.getName();
+            const parentName = block.getParentName();
+            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');
+
+            // Current offset
+            let offsetStr = '';
+
+            // If this block is empty then it's a newline
+            const offsetPadding = 10;
+            const valuePadding = 74;
+            const namePadding = 80;
+            const evmWordStartIndex = 0;
+            const emptySize = 0;
+            let value = '';
+            let nameStr = '';
+            let line = '';
+            if (size === emptySize) {
+                offsetStr = ' '.repeat(offsetPadding);
+                value = ' '.repeat(valuePadding);
+                nameStr = `### ${prettyName.padEnd(namePadding)}`;
+                line = `\n${offsetStr}${value}${nameStr}`;
+            } else {
+                offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES))).padEnd(valuePadding);
+                if (block instanceof MemberCalldataBlock) {
+                    nameStr = `### ${prettyName.padEnd(namePadding)}`;
+                    line = `\n${offsetStr}${value}${nameStr}`;
+                } else {
+                    nameStr = `    ${prettyName.padEnd(namePadding)}`;
+                    line = `${offsetStr}${value}${nameStr}`;
+                }
+            }
+
+            for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) {
+                offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
+                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES))).padEnd(valuePadding);
+                nameStr = ' '.repeat(namePadding);
+                line = `${line}\n${offsetStr}${value}${nameStr}`;
+            }
+
+            // Append to hex value
+            hexValue = `${hexValue}\n${line}`;
+            offset += size;
+        }
+
+        return hexValue;
+    }
+
+    private _generateCondensedHexString(): string {
+        const selectorBuffer = ethUtil.toBuffer(this._selector);
+        if (this._root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = Calldata._createQueue(this._root);
+        const valueBufs: Buffer[] = [selectorBuffer];
+        let block: CalldataBlock | undefined;
+        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
+            valueBufs.push(block.toBuffer());
         }
-        this.sizeInBytes += 8;
+
+        const combinedBuffers = Buffer.concat(valueBufs);
+        const hexValue = ethUtil.bufferToHex(combinedBuffers);
+        return hexValue;
     }
 }
 
 export class RawCalldata {
-    private value: Buffer;
-    private offset: number; // tracks current offset into raw calldata; used for parsing
-    private selector: string;
-    private scopes: Queue<number>;
+    private static readonly _INITIAL_OFFSET = 0;
+    private readonly _value: Buffer;
+    private readonly _selector: string;
+    private readonly _scopes: Queue<number>;
+    private _offset: number; // tracks current offset into raw calldata; used for parsing
 
     constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) {
         if (typeof value === 'string' && !value.startsWith('0x')) {
@@ -492,21 +465,21 @@ export class RawCalldata {
         }
         const valueBuf = ethUtil.toBuffer(value);
         if (hasSelectorPrefix) {
-            this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4));
-            this.value = valueBuf.slice(4); // disregard selector
+            this._selector = ethUtil.bufferToHex(valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES));
+            this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector
         } else {
-            this.selector = '0x';
-            this.value = valueBuf;
+            this._selector = '0x';
+            this._value = valueBuf;
         }
 
-        this.offset = 0;
-        this.scopes = new Queue<number>();
-        this.scopes.push(0);
+        this._scopes = new Queue<number>();
+        this._scopes.push(RawCalldata._INITIAL_OFFSET);
+        this._offset = RawCalldata._INITIAL_OFFSET;
     }
 
     public popBytes(lengthInBytes: number): Buffer {
-        const value = this.value.slice(this.offset, this.offset + lengthInBytes);
-        this.setOffset(this.offset + lengthInBytes);
+        const value = this._value.slice(this._offset, this._offset + lengthInBytes);
+        this.setOffset(this._offset + lengthInBytes);
         return value;
     }
 
@@ -521,28 +494,28 @@ export class RawCalldata {
     }
 
     public readBytes(from: number, to: number): Buffer {
-        const value = this.value.slice(from, to);
+        const value = this._value.slice(from, to);
         return value;
     }
 
-    public setOffset(offsetInBytes: number) {
-        this.offset = offsetInBytes;
+    public setOffset(offsetInBytes: number): void {
+        this._offset = offsetInBytes;
     }
 
-    public startScope() {
-        this.scopes.pushFront(this.offset);
+    public startScope(): void {
+        this._scopes.pushFront(this._offset);
     }
 
-    public endScope() {
-        this.scopes.pop();
+    public endScope(): void {
+        this._scopes.pop();
     }
 
     public getOffset(): number {
-        return this.offset;
+        return this._offset;
     }
 
-    public toAbsoluteOffset(relativeOffset: number) {
-        const scopeOffset = this.scopes.peek();
+    public toAbsoluteOffset(relativeOffset: number): number {
+        const scopeOffset = this._scopes.peek();
         if (scopeOffset === undefined) {
             throw new Error(`Tried to access undefined scope.`);
         }
@@ -551,6 +524,6 @@ export class RawCalldata {
     }
 
     public getSelector(): string {
-        return this.selector;
+        return this._selector;
     }
 }
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 80797c563..926023468 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -78,7 +78,6 @@ export abstract class PayloadDataType extends DataType {
             name,
             signature,
             parentName,
-            /*offsetInBytes,*/ relocatable,
             encodedValue,
         );
         return block;
@@ -116,12 +115,10 @@ export abstract class DependentDataType extends DataType {
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const relocatable = false;
         const block = new DependentCalldataBlock(
             name,
             signature,
             parentName,
-            relocatable,
             dependencyBlock,
             parentBlock,
         );
@@ -235,9 +232,7 @@ export abstract class MemberDataType extends DataType {
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
             this.getDataItem().name,
             this.getSignature(),
-            parentName,
-            this.isStatic(),
-            false,
+            parentName
         );
 
         let members = this.members;
@@ -262,9 +257,7 @@ export abstract class MemberDataType extends DataType {
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
             this.getDataItem().name,
             this.getSignature(),
-            parentName,
-            this.isStatic(),
-            false,
+            parentName
         );
         const memberBlocks: CalldataBlock[] = [];
         let childMap = _.cloneDeep(this.memberMap);
-- 
cgit v1.2.3


From 0f7abcd59bcbad5a74c7984b199158f5c9f03934 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 10:08:17 -0800
Subject: Moved global constants to separate file

---
 packages/utils/src/abi_encoder/constants.ts | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 packages/utils/src/abi_encoder/constants.ts

diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts
new file mode 100644
index 000000000..b52630d74
--- /dev/null
+++ b/packages/utils/src/abi_encoder/constants.ts
@@ -0,0 +1,6 @@
+export const EVM_WORD_WIDTH_IN_BYTES = 32;
+export const HEX_BASE = 16;
+export const BIN_BASE = 2;
+export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
+export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
+export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
\ No newline at end of file
-- 
cgit v1.2.3


From fbbca8e2837b8036b8dfd7985c702fd05073daa3 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 10:09:38 -0800
Subject: Ran prettier on utils

---
 packages/utils/src/abi_encoder/calldata.ts       |  33 +--
 packages/utils/src/abi_encoder/constants.ts      |   2 +-
 packages/utils/src/abi_encoder/data_type.ts      |  19 +-
 packages/utils/src/abi_encoder/evm_data_types.ts |   4 +-
 packages/utils/test/abi_encoder_test.ts          |   4 +-
 packages/utils/test/optimizer_abis.ts            | 339 +++++++++++++++++++++++
 packages/utils/test/return_value_abis.ts         |  98 +++++++
 7 files changed, 463 insertions(+), 36 deletions(-)
 create mode 100644 packages/utils/test/optimizer_abis.ts
 create mode 100644 packages/utils/test/return_value_abis.ts

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 9f91f8495..0c45d6198 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -90,12 +90,7 @@ export abstract class CalldataBlock {
 export class PayloadCalldataBlock extends CalldataBlock {
     private readonly _payload: Buffer;
 
-    constructor(
-        name: string,
-        signature: string,
-        parentName: string,
-        payload: Buffer,
-    ) {
+    constructor(name: string, signature: string, parentName: string, payload: Buffer) {
         const headerSizeInBytes = 0;
         const bodySizeInBytes = payload.byteLength;
         super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
@@ -120,13 +115,7 @@ export class DependentCalldataBlock extends CalldataBlock {
     private readonly _dependency: CalldataBlock;
     private _aliasFor: CalldataBlock | undefined;
 
-    constructor(
-        name: string,
-        signature: string,
-        parentName: string,
-        dependency: CalldataBlock,
-        parent: CalldataBlock,
-    ) {
+    constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) {
         const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE;
         const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
         super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
@@ -408,7 +397,13 @@ export class Calldata {
                 line = `\n${offsetStr}${value}${nameStr}`;
             } else {
                 offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES))).padEnd(valuePadding);
+                value = ethUtil
+                    .stripHexPrefix(
+                        ethUtil.bufferToHex(
+                            block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES),
+                        ),
+                    )
+                    .padEnd(valuePadding);
                 if (block instanceof MemberCalldataBlock) {
                     nameStr = `### ${prettyName.padEnd(namePadding)}`;
                     line = `\n${offsetStr}${value}${nameStr}`;
@@ -420,7 +415,11 @@ export class Calldata {
 
             for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) {
                 offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
-                value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES))).padEnd(valuePadding);
+                value = ethUtil
+                    .stripHexPrefix(
+                        ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)),
+                    )
+                    .padEnd(valuePadding);
                 nameStr = ' '.repeat(namePadding);
                 line = `${line}\n${offsetStr}${value}${nameStr}`;
             }
@@ -465,7 +464,9 @@ export class RawCalldata {
         }
         const valueBuf = ethUtil.toBuffer(value);
         if (hasSelectorPrefix) {
-            this._selector = ethUtil.bufferToHex(valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES));
+            this._selector = ethUtil.bufferToHex(
+                valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES),
+            );
             this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector
         } else {
             this._selector = '0x';
diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts
index b52630d74..bc5b985e0 100644
--- a/packages/utils/src/abi_encoder/constants.ts
+++ b/packages/utils/src/abi_encoder/constants.ts
@@ -3,4 +3,4 @@ export const HEX_BASE = 16;
 export const BIN_BASE = 2;
 export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
 export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
-export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
\ No newline at end of file
+export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 926023468..4370cb253 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -74,12 +74,7 @@ export abstract class PayloadDataType extends DataType {
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
         const relocatable = false;
-        const block = new PayloadCalldataBlock(
-            name,
-            signature,
-            parentName,
-            encodedValue,
-        );
+        const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
         return block;
     }
 
@@ -115,13 +110,7 @@ export abstract class DependentDataType extends DataType {
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const block = new DependentCalldataBlock(
-            name,
-            signature,
-            parentName,
-            dependencyBlock,
-            parentBlock,
-        );
+        const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock);
         return block;
     }
 
@@ -232,7 +221,7 @@ export abstract class MemberDataType extends DataType {
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
             this.getDataItem().name,
             this.getSignature(),
-            parentName
+            parentName,
         );
 
         let members = this.members;
@@ -257,7 +246,7 @@ export abstract class MemberDataType extends DataType {
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
             this.getDataItem().name,
             this.getSignature(),
-            parentName
+            parentName,
         );
         const memberBlocks: CalldataBlock[] = [];
         let childMap = _.cloneDeep(this.memberMap);
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index b862e9396..76837361e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -276,7 +276,7 @@ export class Byte extends PayloadDataType {
         if (valueBuf.byteLength > this.width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                valueBuf.byteLength
+                    valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
@@ -548,7 +548,7 @@ export class Method extends MemberDataType {
 export class EvmDataTypeFactory implements DataTypeFactory {
     private static instance: DataTypeFactory;
 
-    private constructor() { }
+    private constructor() {}
 
     public static getInstance(): DataTypeFactory {
         if (!EvmDataTypeFactory.instance) {
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index 0220984b0..c7986fa00 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -102,7 +102,7 @@ describe.only('ABI Encoder', () => {
         it('Duplicate Dynamic Arrays with Dynamic Elements', async () => {
             // Generate calldata
             const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements);
-            const array1 = ["Hello", "World"];
+            const array1 = ['Hello', 'World'];
             const array2 = array1;
             const args = [array1, array2];
             // Validata calldata
@@ -138,7 +138,7 @@ describe.only('ABI Encoder', () => {
         it('Duplicate Static Arrays with Dynamic Elements', async () => {
             // Generate calldata
             const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements);
-            const array1 = ["Hello", "World"];
+            const array1 = ['Hello', 'World'];
             const array2 = array1;
             const args = [array1, array2];
             // Validata calldata
diff --git a/packages/utils/test/optimizer_abis.ts b/packages/utils/test/optimizer_abis.ts
new file mode 100644
index 000000000..ea562e5b5
--- /dev/null
+++ b/packages/utils/test/optimizer_abis.ts
@@ -0,0 +1,339 @@
+import { MethodAbi } from 'ethereum-types';
+
+export const duplicateDynamicArraysWithStaticElements = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'uint[]',
+        },
+        {
+            name: 'array2',
+            type: 'uint[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateDynamicArraysWithDynamicElements = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'string[]',
+        },
+        {
+            name: 'array2',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateStaticArraysWithStaticElements = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'uint[2]',
+        },
+        {
+            name: 'array2',
+            type: 'uint[2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateStaticArraysWithDynamicElements = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'string[2]',
+        },
+        {
+            name: 'array2',
+            type: 'string[2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateArrayElements = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateTupleFields = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'field1',
+                    type: 'string',
+                },
+                {
+                    name: 'field2',
+                    type: 'string',
+                },
+            ],
+            name: 'Tuple',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateStrings = {
+    constant: false,
+    inputs: [
+        {
+            name: 'string1',
+            type: 'string',
+        },
+        {
+            name: 'string2',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateBytes = {
+    constant: false,
+    inputs: [
+        {
+            name: 'bytes1',
+            type: 'bytes',
+        },
+        {
+            name: 'bytes2',
+            type: 'bytes',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateTuples = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'field1',
+                    type: 'string',
+                },
+                {
+                    name: 'field2',
+                    type: 'uint',
+                },
+            ],
+            name: 'Tuple',
+            type: 'tuple',
+        },
+        {
+            components: [
+                {
+                    name: 'field1',
+                    type: 'string',
+                },
+                {
+                    name: 'field2',
+                    type: 'uint',
+                },
+            ],
+            name: 'Tuple',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateArraysNestedInTuples = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'field',
+                    type: 'uint[]',
+                },
+            ],
+            name: 'Tuple1',
+            type: 'tuple',
+        },
+        {
+            components: [
+                {
+                    name: 'field',
+                    type: 'uint[]',
+                },
+                {
+                    name: 'extraField',
+                    type: 'string',
+                },
+            ],
+            name: 'Tuple2',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateTuplesNestedInTuples = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    components: [
+                        {
+                            name: 'nestedField',
+                            type: 'string',
+                        },
+                    ],
+                    name: 'field',
+                    type: 'tuple',
+                },
+            ],
+            name: 'Tuple1',
+            type: 'tuple',
+        },
+        {
+            components: [
+                {
+                    components: [
+                        {
+                            name: 'nestedField',
+                            type: 'string',
+                        },
+                    ],
+                    name: 'field',
+                    type: 'tuple',
+                },
+                {
+                    name: 'extraField',
+                    type: 'string',
+                },
+            ],
+            name: 'Tuple1',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const duplicateTwoDimensionalArrays = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'string[][]',
+        },
+        {
+            name: 'array2',
+            type: 'string[][]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayElementsDuplicatedAsSeparateParameter = {
+    constant: false,
+    inputs: [
+        {
+            name: 'stringArray',
+            type: 'string[]',
+        },
+        {
+            name: 'string',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const arrayElementsDuplicatedAsTupleFields = {
+    constant: false,
+    inputs: [
+        {
+            name: 'uint8Array',
+            type: 'uint8[]',
+        },
+        {
+            components: [
+                {
+                    name: 'uint',
+                    type: 'uint',
+                },
+            ],
+            name: 'uintTuple',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
diff --git a/packages/utils/test/return_value_abis.ts b/packages/utils/test/return_value_abis.ts
new file mode 100644
index 000000000..847559dac
--- /dev/null
+++ b/packages/utils/test/return_value_abis.ts
@@ -0,0 +1,98 @@
+import { MethodAbi } from 'ethereum-types';
+
+export const noReturnValues = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const singleStaticReturnValue = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'Bytes4',
+            type: 'bytes4',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multipleStaticReturnValues = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val1',
+            type: 'bytes4',
+        },
+        {
+            name: 'val2',
+            type: 'bytes4',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const singleDynamicReturnValue = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val',
+            type: 'bytes',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const multipleDynamicReturnValues = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val1',
+            type: 'bytes',
+        },
+        {
+            name: 'val2',
+            type: 'bytes',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
+
+export const mixedStaticAndDynamicReturnValues = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val1',
+            type: 'bytes4',
+        },
+        {
+            name: 'val2',
+            type: 'bytes',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+} as MethodAbi;
-- 
cgit v1.2.3


From 406b5739be91d2a25337b247d31cef720ddd0ae3 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 10:32:31 -0800
Subject: Fixed linter errors on data_type.ts

---
 packages/utils/src/abi_encoder/calldata.ts       |   6 +-
 packages/utils/src/abi_encoder/constants.ts      |   1 +
 packages/utils/src/abi_encoder/data_type.ts      | 312 ++++++++++++-----------
 packages/utils/src/abi_encoder/evm_data_types.ts |  14 +-
 4 files changed, 171 insertions(+), 162 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 0c45d6198..994b0fb81 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -1,5 +1,7 @@
-import ethUtil = require('ethereumjs-util');
-const _ = require('lodash');
+
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
 import * as Constants from './constants';
 
 export interface DecodingRules {
diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts
index bc5b985e0..52029695f 100644
--- a/packages/utils/src/abi_encoder/constants.ts
+++ b/packages/utils/src/abi_encoder/constants.ts
@@ -1,5 +1,6 @@
 export const EVM_WORD_WIDTH_IN_BYTES = 32;
 export const HEX_BASE = 16;
+export const DEC_BASE = 10;
 export const BIN_BASE = 2;
 export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
 export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 4370cb253..ce7b11ef6 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -1,16 +1,21 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../configured_bignumber';
+
+import * as Constants from './constants';
+
 import {
-    RawCalldata,
     Calldata,
     CalldataBlock,
-    PayloadCalldataBlock,
+    DecodingRules,
     DependentCalldataBlock,
+    EncodingRules,
     MemberCalldataBlock,
+    PayloadCalldataBlock,
+    RawCalldata,
 } from './calldata';
-import { MethodAbi, DataItem } from 'ethereum-types';
-import { DecodingRules, EncodingRules } from './calldata';
-import { BigNumber } from '../configured_bignumber';
-import ethUtil = require('ethereumjs-util');
-var _ = require('lodash');
 
 export interface DataTypeFactory {
     create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
@@ -18,29 +23,30 @@ export interface DataTypeFactory {
 }
 
 export abstract class DataType {
-    private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
-    private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
-
-    private dataItem: DataItem;
-    private factory: DataTypeFactory;
+    private static readonly _DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
+    private static readonly _DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
+    private readonly _dataItem: DataItem;
+    private readonly _factory: DataTypeFactory;
 
     constructor(dataItem: DataItem, factory: DataTypeFactory) {
-        this.dataItem = dataItem;
-        this.factory = factory;
+        this._dataItem = dataItem;
+        this._factory = factory;
     }
 
     public getDataItem(): DataItem {
-        return this.dataItem;
+        return this._dataItem;
     }
 
     public getFactory(): DataTypeFactory {
-        return this.factory;
+        return this._factory;
     }
 
     public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
+        const rules_ = rules ? rules : DataType._DEFAULT_ENCODING_RULES;
         const calldata = new Calldata(rules_);
-        if (selector) calldata.setSelector(selector);
+        if (selector) {
+            calldata.setSelector(selector);
+        }
         const block = this.generateCalldataBlock(value);
         calldata.setRoot(block); // @TODO CHANGE
         const calldataHex = calldata.toHexString();
@@ -49,7 +55,7 @@ export abstract class DataType {
 
     public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
         const rawCalldata = new RawCalldata(calldata, hasSelector);
-        const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
+        const rules_ = rules ? rules : DataType._DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
     }
@@ -61,11 +67,11 @@ export abstract class DataType {
 }
 
 export abstract class PayloadDataType extends DataType {
-    protected hasConstantSize: boolean;
+    protected _hasConstantSize: boolean;
 
     public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
         super(dataItem, factory);
-        this.hasConstantSize = hasConstantSize;
+        this._hasConstantSize = hasConstantSize;
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
@@ -73,7 +79,6 @@ export abstract class PayloadDataType extends DataType {
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const relocatable = false;
         const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
         return block;
     }
@@ -84,8 +89,7 @@ export abstract class PayloadDataType extends DataType {
     }
 
     public isStatic(): boolean {
-        // If a payload has a constant size then it's static
-        return this.hasConstantSize;
+        return this._hasConstantSize;
     }
 
     public abstract encodeValue(value: any): Buffer;
@@ -93,20 +97,22 @@ export abstract class PayloadDataType extends DataType {
 }
 
 export abstract class DependentDataType extends DataType {
-    protected dependency: DataType;
-    protected parent: DataType;
+    protected _dependency: DataType;
+    protected _parent: DataType;
+    private readonly _isStatic: boolean;
 
     public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
         super(dataItem, factory);
-        this.dependency = dependency;
-        this.parent = parent;
+        this._dependency = dependency;
+        this._parent = parent;
+        this._isStatic = true;
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
         if (parentBlock === undefined) {
             throw new Error(`DependentDataType requires a parent block to generate its block`);
         }
-        const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
+        const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
@@ -117,16 +123,16 @@ export abstract class DependentDataType extends DataType {
     public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
         const destinationOffsetBuf = calldata.popWord();
         const currentOffset = calldata.getOffset();
-        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
+        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), Constants.HEX_BASE);
         const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
         calldata.setOffset(destinationOffsetAbsolute);
-        const value = this.dependency.generateValue(calldata, rules);
+        const value = this._dependency.generateValue(calldata, rules);
         calldata.setOffset(currentOffset);
         return value;
     }
 
     public isStatic(): boolean {
-        return true;
+        return this._isStatic;
     }
 }
 
@@ -135,11 +141,11 @@ export interface MemberMap {
 }
 
 export abstract class MemberDataType extends DataType {
-    private memberMap: MemberMap;
-    private members: DataType[];
-    private isArray: boolean;
-    protected arrayLength: number | undefined;
-    protected arrayElementType: string | undefined;
+    protected readonly _arrayLength: number | undefined;
+    protected readonly _arrayElementType: string | undefined;
+    private readonly _memberMap: MemberMap;
+    private readonly _members: DataType[];
+    private readonly _isArray: boolean;
 
     public constructor(
         dataItem: DataItem,
@@ -149,70 +155,86 @@ export abstract class MemberDataType extends DataType {
         arrayElementType?: string,
     ) {
         super(dataItem, factory);
-        this.memberMap = {};
-        this.members = [];
-        this.isArray = isArray;
-        this.arrayLength = arrayLength;
-        this.arrayElementType = arrayElementType;
+        this._memberMap = {};
+        this._members = [];
+        this._isArray = isArray;
+        this._arrayLength = arrayLength;
+        this._arrayElementType = arrayElementType;
         if (isArray && arrayLength !== undefined) {
-            [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
+            [this._members, this._memberMap] = this._createMembersWithLength(dataItem, arrayLength);
         } else if (!isArray) {
-            [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
+            [this._members, this._memberMap] = this._createMembersWithKeys(dataItem);
         }
     }
 
-    private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
-        // Sanity check
-        if (dataItem.components === undefined) {
-            throw new Error(`Expected components`);
-        }
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const block =
+            value instanceof Array
+                ? this._generateCalldataBlockFromArray(value, parentBlock)
+                : this._generateCalldataBlockFromObject(value, parentBlock);
+        return block;
+    }
 
-        let members: DataType[] = [];
-        let memberMap: MemberMap = {};
-        _.each(dataItem.components, (memberItem: DataItem) => {
-            const childDataItem = {
-                type: memberItem.type,
-                name: `${dataItem.name}.${memberItem.name}`,
-            } as DataItem;
-            const components = memberItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[memberItem.name] = members.length;
-            members.push(child);
-        });
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
+        let members = this._members;
+        if (this._isArray && this._arrayLength === undefined) {
+            const arrayLengthBuf = calldata.popWord();
+            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+            const hexBase = 16;
+            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
 
-        return [members, memberMap];
+            [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+        }
+
+        calldata.startScope();
+        let value: any[] | object;
+        if (rules.structsAsObjects && !this._isArray) {
+            value = {};
+            _.each(this._memberMap, (idx: number, key: string) => {
+                const member = this._members[idx];
+                const memberValue = member.generateValue(calldata, rules);
+                (value as { [key: string]: any })[key] = memberValue;
+            });
+        } else {
+            value = [];
+            _.each(members, (member: DataType, idx: number) => {
+                const memberValue = member.generateValue(calldata, rules);
+                (value as any[]).push(memberValue);
+            });
+        }
+        calldata.endScope();
+        return value;
     }
 
-    private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
-        let members: DataType[] = [];
-        let memberMap: MemberMap = {};
-        const range = _.range(length);
-        _.each(range, (idx: number) => {
-            const childDataItem = {
-                type: this.arrayElementType,
-                name: `${dataItem.name}[${idx.toString(10)}]`,
-            } as DataItem;
-            const components = dataItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[idx.toString(10)] = members.length;
-            members.push(child);
-        });
+    public isStatic(): boolean {
+        /* For Tuple:
+                    const isStaticTuple = this.children.length === 0;
+                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
 
-        return [members, memberMap];
+           For Array:
+                if isLengthDefined = false then this is false
+
+                Otherwise if the first element is a Pointer then false
+        */
+
+        if (this._isArray && this._arrayLength === undefined) {
+            return false;
+        }
+
+        // Search for dependent members
+        const dependentMember = _.find(this._members, (member: DataType) => {
+            return member instanceof DependentDataType;
+        });
+        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
+        return isStatic;
     }
 
-    protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
+    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
         // Sanity check length
-        if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
+        if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
             throw new Error(
                 `Expected array of ${JSON.stringify(
-                    this.arrayLength,
+                    this._arrayLength,
                 )} elements, but got array of length ${JSON.stringify(value.length)}`,
             );
         }
@@ -224,11 +246,11 @@ export abstract class MemberDataType extends DataType {
             parentName,
         );
 
-        let members = this.members;
-        if (this.isArray && this.arrayLength === undefined) {
-            [members] = this.createMembersWithLength(this.getDataItem(), value.length);
+        let members = this._members;
+        if (this._isArray && this._arrayLength === undefined) {
+            [members] = this._createMembersWithLength(this.getDataItem(), value.length);
 
-            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
+            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
             methodBlock.setHeader(lenBuf);
         }
 
@@ -241,7 +263,7 @@ export abstract class MemberDataType extends DataType {
         return methodBlock;
     }
 
-    protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
         const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
             this.getDataItem().name,
@@ -249,14 +271,14 @@ export abstract class MemberDataType extends DataType {
             parentName,
         );
         const memberBlocks: CalldataBlock[] = [];
-        let childMap = _.cloneDeep(this.memberMap);
+        const childMap = _.cloneDeep(this._memberMap);
         _.forOwn(obj, (value: any, key: string) => {
-            if (key in childMap === false) {
+            if (!(key in childMap)) {
                 throw new Error(
                     `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
                 );
             }
-            const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
+            const block = this._members[this._memberMap[key]].generateCalldataBlock(value, methodBlock);
             memberBlocks.push(block);
             delete childMap[key];
         });
@@ -269,51 +291,12 @@ export abstract class MemberDataType extends DataType {
         return methodBlock;
     }
 
-    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block =
-            value instanceof Array
-                ? this.generateCalldataBlockFromArray(value, parentBlock)
-                : this.generateCalldataBlockFromObject(value, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
-        let members = this.members;
-        if (this.isArray && this.arrayLength === undefined) {
-            const arrayLengthBuf = calldata.popWord();
-            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const hexBase = 16;
-            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
-            [members] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
-        }
-
-        calldata.startScope();
-        let value: any[] | object;
-        if (rules.structsAsObjects && !this.isArray) {
-            value = {};
-            _.each(this.memberMap, (idx: number, key: string) => {
-                const member = this.members[idx];
-                let memberValue = member.generateValue(calldata, rules);
-                (value as { [key: string]: any })[key] = memberValue;
-            });
-        } else {
-            value = [];
-            _.each(members, (member: DataType, idx: number) => {
-                let memberValue = member.generateValue(calldata, rules);
-                (value as any[]).push(memberValue);
-            });
-        }
-        calldata.endScope();
-        return value;
-    }
-
-    protected computeSignatureOfMembers(): string {
+    protected _computeSignatureOfMembers(): string {
         // Compute signature of members
         let signature = `(`;
-        _.each(this.members, (member: DataType, i: number) => {
+        _.each(this._members, (member: DataType, i: number) => {
             signature += member.getSignature();
-            if (i < this.members.length - 1) {
+            if (i < this._members.length - 1) {
                 signature += ',';
             }
         });
@@ -321,26 +304,49 @@ export abstract class MemberDataType extends DataType {
         return signature;
     }
 
-    public isStatic(): boolean {
-        /* For Tuple:
-                    const isStaticTuple = this.children.length === 0;
-                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
-           For Array:
-                if isLengthDefined = false then this is false
+    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+        // Sanity check
+        if (dataItem.components === undefined) {
+            throw new Error(`Expected components`);
+        }
 
-                Otherwise if the first element is a Pointer then false
-        */
+        const members: DataType[] = [];
+        const memberMap: MemberMap = {};
+        _.each(dataItem.components, (memberItem: DataItem) => {
+            const childDataItem: DataItem = {
+                type: memberItem.type,
+                name: `${dataItem.name}.${memberItem.name}`,
+            };
+            const components = memberItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[memberItem.name] = members.length;
+            members.push(child);
+        });
 
-        if (this.isArray && this.arrayLength === undefined) {
-            return false;
-        }
+        return [members, memberMap];
+    }
 
-        // Search for dependent members
-        const dependentMember = _.find(this.members, (member: DataType) => {
-            return member instanceof DependentDataType;
+    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        const members: DataType[] = [];
+        const memberMap: MemberMap = {};
+        const range = _.range(length);
+        _.each(range, (idx: number) => {
+            const childDataItem: DataItem = {
+                type: this._arrayElementType ? this._arrayElementType : '',
+                name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
+            };
+            const components = dataItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[idx.toString(Constants.DEC_BASE)] = members.length;
+            members.push(child);
         });
-        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
-        return isStatic;
+
+        return [members, memberMap];
     }
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 76837361e..1f5dff56f 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -276,7 +276,7 @@ export class Byte extends PayloadDataType {
         if (valueBuf.byteLength > this.width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                    valueBuf.byteLength
+                valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
@@ -396,7 +396,7 @@ export class Pointer extends DependentDataType {
     }
 
     public getSignature(): string {
-        return this.dependency.getSignature();
+        return this._dependency.getSignature();
     }
 }
 
@@ -408,7 +408,7 @@ export class Tuple extends MemberDataType {
         if (!Tuple.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
         }
-        this.tupleSignature = this.computeSignatureOfMembers();
+        this.tupleSignature = this._computeSignatureOfMembers();
     }
 
     public getSignature(): string {
@@ -455,10 +455,10 @@ export class SolArray extends MemberDataType {
         }
         const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
         const type = elementDataType.getSignature();
-        if (this.arrayLength === undefined) {
+        if (this._arrayLength === undefined) {
             return `${type}[]`;
         } else {
-            return `${type}[${this.arrayLength}]`;
+            return `${type}[${this._arrayLength}]`;
         }
     }
 
@@ -493,7 +493,7 @@ export class Method extends MemberDataType {
     }
 
     private computeSignature(): string {
-        const memberSignature = this.computeSignatureOfMembers();
+        const memberSignature = this._computeSignatureOfMembers();
         const methodSignature = `${this.getDataItem().name}${memberSignature}`;
         return methodSignature;
     }
@@ -548,7 +548,7 @@ export class Method extends MemberDataType {
 export class EvmDataTypeFactory implements DataTypeFactory {
     private static instance: DataTypeFactory;
 
-    private constructor() {}
+    private constructor() { }
 
     public static getInstance(): DataTypeFactory {
         if (!EvmDataTypeFactory.instance) {
-- 
cgit v1.2.3


From 0ed1819143fa82163502fb412bcb5ed44c041456 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 11:14:02 -0800
Subject: Fixed linter errors on evm_data_types

---
 packages/utils/src/abi_encoder/constants.ts      |   1 +
 packages/utils/src/abi_encoder/evm_data_types.ts | 383 +++++++++++------------
 2 files changed, 190 insertions(+), 194 deletions(-)

diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts
index 52029695f..3d85fbdb8 100644
--- a/packages/utils/src/abi_encoder/constants.ts
+++ b/packages/utils/src/abi_encoder/constants.ts
@@ -1,4 +1,5 @@
 export const EVM_WORD_WIDTH_IN_BYTES = 32;
+export const EVM_WORD_WIDTH_IN_BITS = 256;
 export const HEX_BASE = 16;
 export const DEC_BASE = 10;
 export const BIN_BASE = 2;
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 1f5dff56f..24f6051b0 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -1,16 +1,12 @@
-import { DataType, DataTypeFactory, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
-
-import { DecodingRules, EncodingRules } from './calldata';
-
-import { MethodAbi, DataItem } from 'ethereum-types';
-
-import ethUtil = require('ethereumjs-util');
-
-import { Calldata, RawCalldata } from './calldata';
+import { DataItem, MethodAbi } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
 
 import { BigNumber } from '../configured_bignumber';
 
-var _ = require('lodash');
+import { DecodingRules, EncodingRules, RawCalldata } from './calldata';
+import * as Constants from './constants';
+import { DataType, DataTypeFactory, DependentDataType, MemberDataType, PayloadDataType } from './data_type';
 
 export interface DataTypeStaticInterface {
     matchGrammar: (type: string) => boolean;
@@ -19,12 +15,18 @@ export interface DataTypeStaticInterface {
 }
 
 export class Address extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
     public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes';
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
+    private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES - Address._ADDRESS_SIZE_IN_BYTES;
+
+    public static matchGrammar(type: string): boolean {
+        return type === 'address';
+    }
 
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME);
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Address._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!Address.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
         }
@@ -34,36 +36,35 @@ export class Address extends PayloadDataType {
         return 'address';
     }
 
-    public static matchGrammar(type: string): boolean {
-        return type === 'address';
-    }
-
     public encodeValue(value: string): Buffer {
-        if (value.startsWith('0x') === false) {
+        if (!value.startsWith('0x')) {
             throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
         }
         const valueAsBuffer = ethUtil.toBuffer(value);
-        if (valueAsBuffer.byteLength !== 20) {
+        if (valueAsBuffer.byteLength !== Address._ADDRESS_SIZE_IN_BYTES) {
             throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
         }
-        const evmWordWidth = 32;
-        const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, evmWordWidth);
+        const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, Constants.EVM_WORD_WIDTH_IN_BYTES);
         return encodedValueBuf;
     }
 
     public decodeValue(calldata: RawCalldata): string {
         const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(12);
+        const valueBuf = paddedValueBuf.slice(Address._DECODED_ADDRESS_OFFSET_IN_BYTES);
         const value = ethUtil.bufferToHex(valueBuf);
         return value;
     }
 }
 
 export class Bool extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bool.SIZE_KNOWN_AT_COMPILE_TIME);
+    public static matchGrammar(type: string): boolean {
+        return type === 'bool';
+    }
+
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bool._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!Bool.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
         }
@@ -73,14 +74,9 @@ export class Bool extends PayloadDataType {
         return 'bool';
     }
 
-    public static matchGrammar(type: string): boolean {
-        return type === 'bool';
-    }
-
     public encodeValue(value: boolean): Buffer {
-        const evmWordWidth = 32;
-        const encodedValue = value === true ? '0x1' : '0x0';
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), evmWordWidth);
+        const encodedValue = value ? '0x1' : '0x0';
+        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), Constants.EVM_WORD_WIDTH_IN_BYTES);
         return encodedValueBuf;
     }
 
@@ -88,46 +84,44 @@ export class Bool extends PayloadDataType {
         const valueBuf = calldata.popWord();
         const valueHex = ethUtil.bufferToHex(valueBuf);
         const valueNumber = new BigNumber(valueHex, 16);
-        let value: boolean = valueNumber.equals(0) ? false : true;
         if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
             throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
         }
+        /* tslint:disable boolean-naming */
+        const value: boolean = valueNumber.equals(0) ? false : true;
+        /* tslint:enable boolean-naming */
         return value;
     }
 }
 
 abstract class Number extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    static MAX_WIDTH: number = 256;
-    static DEFAULT_WIDTH: number = Number.MAX_WIDTH;
-    width: number = Number.DEFAULT_WIDTH;
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _MAX_WIDTH: number = 256;
+    private static readonly _DEFAULT_WIDTH: number = Number._MAX_WIDTH;
+    protected _width: number;
 
     constructor(dataItem: DataItem, matcher: RegExp) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Number.SIZE_KNOWN_AT_COMPILE_TIME);
+        super(dataItem, EvmDataTypeFactory.getInstance(), Number._SIZE_KNOWN_AT_COMPILE_TIME);
         const matches = matcher.exec(dataItem.type);
         if (matches === null) {
             throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
         }
-        if (matches !== null && matches.length === 2 && matches[1] !== undefined) {
-            this.width = parseInt(matches[1]);
-        } else {
-            this.width = 256;
-        }
+        this._width = (matches !== null && matches.length === 2 && matches[1] !== undefined) ?
+            parseInt(matches[1], Constants.DEC_BASE) :
+            this._width = Number._DEFAULT_WIDTH;
     }
 
     public encodeValue(value_: BigNumber | string | number): Buffer {
         const value = new BigNumber(value_, 10);
         if (value.greaterThan(this.getMaxValue())) {
-            throw `Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`;
+            throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`);
         } else if (value.lessThan(this.getMinValue())) {
-            throw `Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`;
+            throw new Error(`Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`);
         }
 
-        const hexBase = 16;
-        const evmWordWidth = 32;
         let valueBuf: Buffer;
         if (value.greaterThanOrEqualTo(0)) {
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(hexBase)}`), evmWordWidth);
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
         } else {
             // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
             // Step 1/3: Convert value to positive binary string
@@ -135,8 +129,7 @@ abstract class Number extends PayloadDataType {
             const valueBin = value.times(-1).toString(binBase);
 
             // Step 2/3: Invert binary value
-            const bitsInEvmWord = 256;
-            let invertedValueBin = '1'.repeat(bitsInEvmWord - valueBin.length);
+            let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
             _.each(valueBin, (bit: string) => {
                 invertedValueBin += bit === '1' ? '0' : '1';
             });
@@ -147,7 +140,7 @@ abstract class Number extends PayloadDataType {
             const negativeValue = invertedValue.plus(1);
 
             // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${negativeValue.toString(hexBase)}`), evmWordWidth);
+            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${negativeValue.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
         }
 
         return valueBuf;
@@ -159,16 +152,15 @@ abstract class Number extends PayloadDataType {
         let value = new BigNumber(paddedValueHex, 16);
         if (this instanceof Int) {
             // Check if we're negative
-            const binBase = 2;
-            const valueBin = value.toString(2);
-            if (valueBin.length === 256 && valueBin[0].startsWith('1')) {
+            const valueBin = value.toString(Constants.BIN_BASE);
+            if (valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1')) {
                 // Negative
                 // Step 1/3: Invert binary value
                 let invertedValueBin = '';
                 _.each(valueBin, (bit: string) => {
                     invertedValueBin += bit === '1' ? '0' : '1';
                 });
-                const invertedValue = new BigNumber(invertedValueBin, binBase);
+                const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
 
                 // Step 2/3: Add 1 to inverted value
                 // The result is the two's-complement represent of the input value.
@@ -188,42 +180,46 @@ abstract class Number extends PayloadDataType {
 }
 
 export class Int extends Number {
-    static matcher = RegExp(
+    private static readonly _matcher = RegExp(
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
 
-    constructor(dataItem: DataItem) {
-        super(dataItem, Int.matcher);
+    public static matchGrammar(type: string): boolean {
+        return Int._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem) {
+        super(dataItem, Int._matcher);
     }
 
     public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).sub(1);
+        return new BigNumber(2).toPower(this._width - 1).sub(1);
     }
 
     public getMinValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width - 1).times(-1);
+        return new BigNumber(2).toPower(this._width - 1).times(-1);
     }
 
     public getSignature(): string {
-        return `int${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
+        return `int${this._width}`;
     }
 }
 
 export class UInt extends Number {
-    static matcher = RegExp(
+    private static readonly _matcher = RegExp(
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
 
-    constructor(dataItem: DataItem) {
-        super(dataItem, UInt.matcher);
+    public static matchGrammar(type: string): boolean {
+        return UInt._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem) {
+        super(dataItem, UInt._matcher);
     }
 
     public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this.width).sub(1);
+        return new BigNumber(2).toPower(this._width).sub(1);
     }
 
     public getMinValue(): BigNumber {
@@ -231,49 +227,45 @@ export class UInt extends Number {
     }
 
     public getSignature(): string {
-        return `uint${this.width}`;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
+        return `uint${this._width}`;
     }
 }
 
 export class Byte extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    static matcher = RegExp(
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _matcher = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
     );
 
-    static DEFAULT_WIDTH = 1;
-    width: number = Byte.DEFAULT_WIDTH;
+    private static readonly _DEFAULT_WIDTH = 1;
+    private readonly _width: number;
+
+    public static matchGrammar(type: string): boolean {
+        return Byte._matcher.test(type);
+    }
 
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Byte.SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = Byte.matcher.exec(dataItem.type);
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Byte._SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = Byte._matcher.exec(dataItem.type);
         if (!Byte.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
         }
-        if (matches !== null && matches.length === 3 && matches[2] !== undefined) {
-            this.width = parseInt(matches[2]);
-        } else {
-            this.width = Byte.DEFAULT_WIDTH;
-        }
+        this._width = (matches !== null && matches.length === 3 && matches[2] !== undefined) ? parseInt(matches[2], Constants.DEC_BASE) : Byte._DEFAULT_WIDTH;
     }
 
     public getSignature(): string {
         // Note that `byte` reduces to `bytes1`
-        return `bytes${this.width}`;
+        return `bytes${this._width}`;
     }
 
     public encodeValue(value: string | Buffer): Buffer {
         // Sanity check if string
-        if (typeof value === 'string' && value.startsWith('0x') === false) {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
             throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
         }
         // Convert value into a buffer and do bounds checking
         const valueBuf = ethUtil.toBuffer(value);
-        if (valueBuf.byteLength > this.width) {
+        if (valueBuf.byteLength > this._width) {
             throw new Error(
                 `Tried to assign ${value} (${
                 valueBuf.byteLength
@@ -291,23 +283,21 @@ export class Byte extends PayloadDataType {
 
     public decodeValue(calldata: RawCalldata): string {
         const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(0, this.width);
+        const valueBuf = paddedValueBuf.slice(0, this._width);
         const value = ethUtil.bufferToHex(valueBuf);
         return value;
     }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
 }
 
 export class Bytes extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-    static UNDEFINED_LENGTH = new BigNumber(-1);
-    length: BigNumber = Bytes.UNDEFINED_LENGTH;
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes.SIZE_KNOWN_AT_COMPILE_TIME);
+    public static matchGrammar(type: string): boolean {
+        return type === 'bytes';
+    }
+
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!Bytes.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
         }
@@ -322,10 +312,10 @@ export class Bytes extends PayloadDataType {
             throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
         }
 
-        const wordsForValue = Math.ceil(valueBuf.byteLength / 32);
-        const paddedBytesForValue = wordsForValue * 32;
+        const wordsForValue = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const paddedBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
         const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
-        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), 32);
+        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), Constants.EVM_WORD_WIDTH_IN_BYTES);
         const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
         return encodedValueBuf;
     }
@@ -333,8 +323,8 @@ export class Bytes extends PayloadDataType {
     public decodeValue(calldata: RawCalldata): string {
         const lengthBuf = calldata.popWord();
         const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, 16);
-        const wordsForValue = Math.ceil(length / 32);
+        const length = parseInt(lengthHex, Constants.HEX_BASE);
+        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
         const paddedValueBuf = calldata.popWords(wordsForValue);
         const valueBuf = paddedValueBuf.slice(0, length);
         const decodedValue = ethUtil.bufferToHex(valueBuf);
@@ -344,26 +334,27 @@ export class Bytes extends PayloadDataType {
     public getSignature(): string {
         return 'bytes';
     }
+}
+
+export class SolString extends PayloadDataType {
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchGrammar(type: string): boolean {
-        return type === 'bytes';
+        return type === 'string';
     }
-}
 
-export class SolString extends PayloadDataType {
-    private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-    constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), SolString.SIZE_KNOWN_AT_COMPILE_TIME);
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), SolString._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!SolString.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
         }
     }
 
     public encodeValue(value: string): Buffer {
-        const wordsForValue = Math.ceil(value.length / 32);
-        const paddedBytesForValue = wordsForValue * 32;
+        const wordsForValue = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const paddedBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
         const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedBytesForValue);
-        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), 32);
+        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), Constants.EVM_WORD_WIDTH_IN_BYTES);
         const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
         return encodedValueBuf;
     }
@@ -371,8 +362,8 @@ export class SolString extends PayloadDataType {
     public decodeValue(calldata: RawCalldata): string {
         const lengthBuf = calldata.popWord();
         const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, 16);
-        const wordsForValue = Math.ceil(length / 32);
+        const length = parseInt(lengthHex, Constants.HEX_BASE);
+        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
         const paddedValueBuf = calldata.popWords(wordsForValue);
         const valueBuf = paddedValueBuf.slice(0, length);
         const value = valueBuf.toString('ascii');
@@ -382,16 +373,12 @@ export class SolString extends PayloadDataType {
     public getSignature(): string {
         return 'string';
     }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'string';
-    }
 }
 
 export class Pointer extends DependentDataType {
     constructor(destDataType: DataType, parentDataType: DataType) {
         const destDataItem = destDataType.getDataItem();
-        const dataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` } as DataItem;
+        const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` };
         super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
     }
 
@@ -401,33 +388,37 @@ export class Pointer extends DependentDataType {
 }
 
 export class Tuple extends MemberDataType {
-    private tupleSignature: string;
+    private readonly _tupleSignature: string;
 
-    constructor(dataItem: DataItem) {
+    public static matchGrammar(type: string): boolean {
+        return type === 'tuple';
+    }
+
+    public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
         if (!Tuple.matchGrammar(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
         }
-        this.tupleSignature = this._computeSignatureOfMembers();
+        this._tupleSignature = this._computeSignatureOfMembers();
     }
 
     public getSignature(): string {
-        return this.tupleSignature;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return type === 'tuple';
+        return this._tupleSignature;
     }
 }
 
 export class SolArray extends MemberDataType {
-    static matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
-    private arraySignature: string;
-    private elementType: string;
+    private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    private readonly _arraySignature: string;
+    private readonly _elementType: string;
 
-    constructor(dataItem: DataItem) {
+    public static matchGrammar(type: string): boolean {
+        return SolArray._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem) {
         // Sanity check
-        const matches = SolArray.matcher.exec(dataItem.type);
+        const matches = SolArray._matcher.exec(dataItem.type);
         if (matches === null || matches.length !== 3) {
             throw new Error(`Could not parse array: ${dataItem.type}`);
         } else if (matches[1] === undefined) {
@@ -438,17 +429,21 @@ export class SolArray extends MemberDataType {
 
         const isArray = true;
         const arrayElementType = matches[1];
-        const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], 10);
+        const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], Constants.DEC_BASE);
         super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
-        this.elementType = arrayElementType;
-        this.arraySignature = this.computeSignature();
+        this._elementType = arrayElementType;
+        this._arraySignature = this._computeSignature();
     }
 
-    private computeSignature(): string {
-        let dataItem = {
-            type: this.elementType,
+    public getSignature(): string {
+        return this._arraySignature;
+    }
+
+    private _computeSignature(): string {
+        const dataItem: DataItem = {
+            type: this._elementType,
             name: 'N/A',
-        } as DataItem;
+        };
         const components = this.getDataItem().components;
         if (components !== undefined) {
             dataItem.components = components;
@@ -461,49 +456,29 @@ export class SolArray extends MemberDataType {
             return `${type}[${this._arrayLength}]`;
         }
     }
-
-    public getSignature(): string {
-        return this.arraySignature;
-    }
-
-    public static matchGrammar(type: string): boolean {
-        return this.matcher.test(type);
-    }
 }
 
 export class Method extends MemberDataType {
-    private methodSignature: string;
-    private methodSelector: string;
-    private returnDataTypes: DataType[];
-    private returnDataItem: DataItem;
-
     // TMP
     public selector: string;
 
-    constructor(abi: MethodAbi) {
+    private readonly _methodSignature: string;
+    private readonly _methodSelector: string;
+    private readonly _returnDataTypes: DataType[];
+    private readonly _returnDataItem: DataItem;
+
+    public constructor(abi: MethodAbi) {
         super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
-        this.methodSignature = this.computeSignature();
-        this.selector = this.methodSelector = this.computeSelector();
-        this.returnDataTypes = [];
-        this.returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
+        this._methodSignature = this._computeSignature();
+        this.selector = this._methodSelector = this._computeSelector();
+        this._returnDataTypes = [];
+        this._returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
         const dummy = new Byte({ type: 'byte', name: 'DUMMY' }); // @TODO TMP
         _.each(abi.outputs, (dataItem: DataItem) => {
-            this.returnDataTypes.push(this.getFactory().create(dataItem, dummy));
+            this._returnDataTypes.push(this.getFactory().create(dataItem, dummy));
         });
     }
 
-    private computeSignature(): string {
-        const memberSignature = this._computeSignatureOfMembers();
-        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
-        return methodSignature;
-    }
-
-    private computeSelector(): string {
-        const signature = this.computeSignature();
-        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(0, 4)));
-        return selector;
-    }
-
     public encode(value: any, rules?: EncodingRules): string {
         const calldata = super.encode(value, rules, this.selector);
         return calldata;
@@ -521,55 +496,73 @@ export class Method extends MemberDataType {
     }
 
     public encodeReturnValues(value: any, rules?: EncodingRules): string {
-        const returnDataType = new Tuple(this.returnDataItem);
+        const returnDataType = new Tuple(this._returnDataItem);
         const returndata = returnDataType.encode(value, rules);
         return returndata;
     }
 
     public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
         const returnValues: any[] = [];
-        const rules_ = rules ? rules : ({ structsAsObjects: false } as DecodingRules);
+        const rules_: DecodingRules = rules ? rules : { structsAsObjects: false };
         const rawReturnData = new RawCalldata(returndata, false);
-        _.each(this.returnDataTypes, (dataType: DataType) => {
+        _.each(this._returnDataTypes, (dataType: DataType) => {
             returnValues.push(dataType.generateValue(rawReturnData, rules_));
         });
         return returnValues;
     }
 
     public getSignature(): string {
-        return this.methodSignature;
+        return this._methodSignature;
     }
 
     public getSelector(): string {
-        return this.methodSelector;
+        return this._methodSelector;
+    }
+
+    private _computeSignature(): string {
+        const memberSignature = this._computeSignatureOfMembers();
+        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
+        return methodSignature;
+    }
+
+    private _computeSelector(): string {
+        const signature = this._computeSignature();
+        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES)));
+        return selector;
     }
 }
 
 export class EvmDataTypeFactory implements DataTypeFactory {
-    private static instance: DataTypeFactory;
-
-    private constructor() { }
+    private static _instance: DataTypeFactory;
 
     public static getInstance(): DataTypeFactory {
-        if (!EvmDataTypeFactory.instance) {
-            EvmDataTypeFactory.instance = new EvmDataTypeFactory();
+        if (!EvmDataTypeFactory._instance) {
+            EvmDataTypeFactory._instance = new EvmDataTypeFactory();
         }
-        return EvmDataTypeFactory.instance;
+        return EvmDataTypeFactory._instance;
     }
 
     public mapDataItemToDataType(dataItem: DataItem): DataType {
-        if (SolArray.matchGrammar(dataItem.type)) return new SolArray(dataItem);
-        if (Address.matchGrammar(dataItem.type)) return new Address(dataItem);
-        if (Bool.matchGrammar(dataItem.type)) return new Bool(dataItem);
-        if (Int.matchGrammar(dataItem.type)) return new Int(dataItem);
-        if (UInt.matchGrammar(dataItem.type)) return new UInt(dataItem);
-        if (Byte.matchGrammar(dataItem.type)) return new Byte(dataItem);
-        if (Tuple.matchGrammar(dataItem.type)) return new Tuple(dataItem);
-        if (Bytes.matchGrammar(dataItem.type)) return new Bytes(dataItem);
-        if (SolString.matchGrammar(dataItem.type)) return new SolString(dataItem);
-        //if (Fixed.matchGrammar(dataItem.type)) return Fixed(dataItem);
-        //if (UFixed.matchGrammar(dataItem.type)) return UFixed(dataItem);
-
+        if (SolArray.matchGrammar(dataItem.type)) {
+            return new SolArray(dataItem);
+        } else if (Address.matchGrammar(dataItem.type)) {
+            return new Address(dataItem);
+        } else if (Bool.matchGrammar(dataItem.type)) {
+            return new Bool(dataItem);
+        } else if (Int.matchGrammar(dataItem.type)) {
+            return new Int(dataItem);
+        } else if (UInt.matchGrammar(dataItem.type)) {
+            return new UInt(dataItem);
+        } else if (Byte.matchGrammar(dataItem.type)) {
+            return new Byte(dataItem);
+        } else if (Tuple.matchGrammar(dataItem.type)) {
+            return new Tuple(dataItem);
+        } else if (Bytes.matchGrammar(dataItem.type)) {
+            return new Bytes(dataItem);
+        } else if (SolString.matchGrammar(dataItem.type)) {
+            return new SolString(dataItem);
+        }
+        // @TODO: Implement Fixed/UFixed types
         throw new Error(`Unrecognized data type: '${dataItem.type}'`);
     }
 
@@ -586,4 +579,6 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         const pointer = new Pointer(dataType, parentDataType);
         return pointer;
     }
+
+    private constructor() { }
 }
-- 
cgit v1.2.3


From 62e6b22789b349dda7885d3317c76c90ecb3c882 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 11:35:16 -0800
Subject: Fixed linter errors on tests

---
 packages/utils/test/abi_encoder_test.ts  | 99 +++++++++++++++++---------------
 packages/utils/test/abi_samples.ts       | 93 +++++++++++++++---------------
 packages/utils/test/optimizer_abis.ts    | 57 +++++++++---------
 packages/utils/test/return_value_abis.ts | 25 ++++----
 4 files changed, 141 insertions(+), 133 deletions(-)

diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index c7986fa00..e99528b06 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -1,13 +1,13 @@
 import * as chai from 'chai';
+import * as ethUtil from 'ethereumjs-util';
 import 'mocha';
 
-import { chaiSetup } from './utils/chai_setup';
-import { BigNumber, AbiEncoder } from '../src/';
+import { AbiEncoder, BigNumber } from '../src/';
+
 import * as AbiSamples from './abi_samples';
 import * as OptimizedAbis from './optimizer_abis';
 import * as ReturnValueAbis from './return_value_abis';
-import { DecodingRules } from '../src/abi_encoder';
-import ethUtil = require('ethereumjs-util');
+import { chaiSetup } from './utils/chai_setup';
 
 chaiSetup.configure();
 const expect = chai.expect;
@@ -349,8 +349,8 @@ describe.only('ABI Encoder', () => {
             // Generate calldata
             const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsSeparateParameter);
             const array = ['Hello', 'Hello', 'Hello', 'World'];
-            const string = 'Hello';
-            const args = [array, string];
+            const str = 'Hello';
+            const args = [array, str];
             // Validate calldata
             const optimizedCalldata = method.encode(args, { optimize: true });
             const expectedOptimizedCalldata =
@@ -392,7 +392,8 @@ describe.only('ABI Encoder', () => {
             const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
             let value = 0;
             const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
+            const arrayOfTuplesLength = 8;
+            for (let i = 0; i < arrayOfTuplesLength; ++i) {
                 arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
             }
             const args = [arrayOfTuples];
@@ -412,7 +413,8 @@ describe.only('ABI Encoder', () => {
             const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
             let value = 0;
             const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
+            const arrayOfTuplesLength = 8;
+            for (let i = 0; i < arrayOfTuplesLength; ++i) {
                 arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
             }
             const args = [arrayOfTuples];
@@ -432,7 +434,8 @@ describe.only('ABI Encoder', () => {
             const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
             let value = 0;
             const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
+            const arrayOfTuplesLength = 8;
+            for (let i = 0; i < arrayOfTuplesLength; ++i) {
                 arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
             }
             const args = [arrayOfTuples];
@@ -452,7 +455,8 @@ describe.only('ABI Encoder', () => {
             const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
             let value = 0;
             const arrayOfTuples = [];
-            for (let i = 0; i < 8; ++i) {
+            const arrayOfTuplesLength = 8;
+            for (let i = 0; i < arrayOfTuplesLength; ++i) {
                 arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
             }
             const args = [arrayOfTuples];
@@ -473,7 +477,8 @@ describe.only('ABI Encoder', () => {
             // Eight 3-dimensional arrays of uint8[2][2][2]
             let value = 0;
             const args = [];
-            for (let i = 0; i < 8; ++i) {
+            const argsLength = 8;
+            for (let i = 0; i < argsLength; ++i) {
                 args.push([
                     [
                         [new BigNumber(++value), new BigNumber(++value)],
@@ -503,7 +508,8 @@ describe.only('ABI Encoder', () => {
             // Eight 3-dimensional arrays of string[2][2][2]
             let value = 0;
             const args = [];
-            for (let i = 0; i < 4; ++i) {
+            const argsLength = 4;
+            for (let i = 0; i < argsLength; ++i) {
                 args.push([
                     [
                         [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
@@ -741,13 +747,13 @@ describe.only('ABI Encoder', () => {
             };
             const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
             const args = {
-                someStaticArray: someStaticArray,
-                someStaticArrayWithDynamicMembers: someStaticArrayWithDynamicMembers,
-                someDynamicArrayWithDynamicMembers: someDynamicArrayWithDynamicMembers,
-                some2DArray: some2DArray,
-                someTuple: someTuple,
-                someTupleWithDynamicTypes: someTupleWithDynamicTypes,
-                someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes,
+                someStaticArray,
+                someStaticArrayWithDynamicMembers,
+                someDynamicArrayWithDynamicMembers,
+                some2DArray,
+                someTuple,
+                someTupleWithDynamicTypes,
+                someArrayOfTuplesWithDynamicTypes,
             };
             const calldata = method.encode(args);
             // Validate calldata
@@ -900,8 +906,6 @@ describe.only('ABI Encoder', () => {
             const args = [array1, array2];
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
-            console.log(encodedArgs);
-            console.log(dataType.encode(args, { annotate: true }));
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000401020304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040910111200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000410111213000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -963,7 +967,7 @@ describe.only('ABI Encoder', () => {
                 '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -985,7 +989,7 @@ describe.only('ABI Encoder', () => {
                 '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -1007,7 +1011,7 @@ describe.only('ABI Encoder', () => {
                 '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -1029,7 +1033,7 @@ describe.only('ABI Encoder', () => {
                 '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -1053,7 +1057,7 @@ describe.only('ABI Encoder', () => {
                 '0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -1077,7 +1081,7 @@ describe.only('ABI Encoder', () => {
                 '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -1109,7 +1113,7 @@ describe.only('ABI Encoder', () => {
                 '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
-            const decodingRules = { structsAsObjects: true } as DecodingRules;
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
             const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const argsAsJson = JSON.stringify(args);
@@ -1224,6 +1228,13 @@ describe.only('ABI Encoder', () => {
     });
 
     describe('Integer', () => {
+        /* tslint:disable custom-no-magic-numbers */
+        const max256BitInteger = new BigNumber(2).pow(255).minus(1);
+        const min256BitInteger = new BigNumber(2).pow(255).times(-1);
+        const max32BitInteger = new BigNumber(2).pow(31).minus(1);
+        const min32BitInteger = new BigNumber(2).pow(31).times(-1);
+        /* tslint:enable custom-no-magic-numbers */
+
         it('Int256 - Positive Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Integer (256)', type: 'int' };
@@ -1261,7 +1272,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max256BitInteger = new BigNumber(2).pow(255).minus(1);
             const args = max256BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1278,7 +1288,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min256BitInteger = new BigNumber(2).pow(255).times(-1);
             const args = min256BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1295,7 +1304,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max256BitInteger = new BigNumber(2).pow(255).minus(1);
             const args = max256BitInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1307,7 +1315,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (256)', type: 'int' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min256BitInteger = new BigNumber(2).pow(255).times(-1);
             const args = min256BitInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1351,7 +1358,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max32BitInteger = new BigNumber(2).pow(31).minus(1);
             const args = max32BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1368,7 +1374,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min32BitInteger = new BigNumber(2).pow(31).times(-1);
             const args = min32BitInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1385,7 +1390,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const max32BitInteger = new BigNumber(2).pow(31).minus(1);
             const args = max32BitInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1397,7 +1401,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Integer (32)', type: 'int32' };
             const dataType = new AbiEncoder.Int(testDataItem);
             // Construct args to be encoded
-            const min32BitInteger = new BigNumber(2).pow(31).times(-1);
             const args = min32BitInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1407,6 +1410,13 @@ describe.only('ABI Encoder', () => {
     });
 
     describe('Unsigned Integer', () => {
+        /* tslint:disable custom-no-magic-numbers */
+        const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
+        const min256BitUnsignedInteger = new BigNumber(0);
+        const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
+        const min32BitUnsignedInteger = new BigNumber(0);
+        /* tslint:enable custom-no-magic-numbers */
+
         it('UInt256 - Positive Base Case', async () => {
             // Create DataType object
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
@@ -1428,7 +1438,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
             const args = max256BitUnsignedInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1445,7 +1454,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const min256BitUnsignedInteger = new BigNumber(0);
             const args = min256BitUnsignedInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1462,7 +1470,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
             const args = max256BitUnsignedInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1474,7 +1481,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const min256BitUnsignedInteger = new BigNumber(0);
             const args = min256BitUnsignedInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1502,7 +1508,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
             const args = max32BitUnsignedInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1519,7 +1524,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const min32BitUnsignedInteger = new BigNumber(0);
             const args = min32BitUnsignedInteger;
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
@@ -1536,7 +1540,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
             const args = max32BitUnsignedInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1548,7 +1551,6 @@ describe.only('ABI Encoder', () => {
             const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
             const dataType = new AbiEncoder.UInt(testDataItem);
             // Construct args to be encoded
-            const min32BitUnsignedInteger = new BigNumber(0);
             const args = min32BitUnsignedInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
@@ -1733,7 +1735,8 @@ describe.only('ABI Encoder', () => {
             const dataType = new AbiEncoder.Bytes(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = '0x' + '61'.repeat(40);
+            const bytesLength = 40;
+            const args = '0x' + '61'.repeat(bytesLength);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
             const expectedEncodedArgs =
@@ -1813,7 +1816,8 @@ describe.only('ABI Encoder', () => {
             const dataType = new AbiEncoder.SolString(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = 'a'.repeat(40);
+            const bytesLength = 40;
+            const args = 'a'.repeat(bytesLength);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
             const expectedEncodedArgs =
@@ -1831,7 +1835,8 @@ describe.only('ABI Encoder', () => {
             const dataType = new AbiEncoder.SolString(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = '0x' + 'a'.repeat(40);
+            const strLength = 40;
+            const args = '0x' + 'a'.repeat(strLength);
             // Encode Args and validate result
             const encodedArgs = dataType.encode(args);
             const expectedEncodedArgs =
diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts
index 0c3354044..fc552c127 100644
--- a/packages/utils/test/abi_samples.ts
+++ b/packages/utils/test/abi_samples.ts
@@ -1,6 +1,7 @@
+/* tslint:disable max-file-line-count */
 import { MethodAbi } from 'ethereum-types';
 
-export const simpleAbi = {
+export const simpleAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -17,9 +18,9 @@ export const simpleAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const stringAbi = {
+export const stringAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -32,9 +33,9 @@ export const stringAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const GAbi = {
+export const GAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -66,9 +67,9 @@ export const GAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const typesWithDefaultWidthsAbi = {
+export const typesWithDefaultWidthsAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -101,9 +102,9 @@ export const typesWithDefaultWidthsAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const multiDimensionalArraysStaticTypeAbi = {
+export const multiDimensionalArraysStaticTypeAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -144,9 +145,9 @@ export const multiDimensionalArraysStaticTypeAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const multiDimensionalArraysDynamicTypeAbi = {
+export const multiDimensionalArraysDynamicTypeAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -171,9 +172,9 @@ export const multiDimensionalArraysDynamicTypeAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const dynamicTupleAbi = {
+export const dynamicTupleAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -196,9 +197,9 @@ export const dynamicTupleAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayOfStaticTuplesWithDefinedLengthAbi = {
+export const arrayOfStaticTuplesWithDefinedLengthAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -221,9 +222,9 @@ export const arrayOfStaticTuplesWithDefinedLengthAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayOfStaticTuplesWithDynamicLengthAbi = {
+export const arrayOfStaticTuplesWithDynamicLengthAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -246,9 +247,9 @@ export const arrayOfStaticTuplesWithDynamicLengthAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayOfDynamicTuplesWithDefinedLengthAbi = {
+export const arrayOfDynamicTuplesWithDefinedLengthAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -271,9 +272,9 @@ export const arrayOfDynamicTuplesWithDefinedLengthAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayOfDynamicTuplesWithUndefinedLengthAbi = {
+export const arrayOfDynamicTuplesWithUndefinedLengthAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -296,9 +297,9 @@ export const arrayOfDynamicTuplesWithUndefinedLengthAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayOfDynamicTuplesAbi = {
+export const arrayOfDynamicTuplesAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -321,9 +322,9 @@ export const arrayOfDynamicTuplesAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const multidimensionalArrayOfDynamicTuplesAbi = {
+export const multidimensionalArrayOfDynamicTuplesAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -346,9 +347,9 @@ export const multidimensionalArrayOfDynamicTuplesAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const staticTupleAbi = {
+export const staticTupleAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -379,9 +380,9 @@ export const staticTupleAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const staticArrayAbi = {
+export const staticArrayAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -394,9 +395,9 @@ export const staticArrayAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const staticArrayDynamicMembersAbi = {
+export const staticArrayDynamicMembersAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -409,9 +410,9 @@ export const staticArrayDynamicMembersAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const dynamicArrayDynamicMembersAbi = {
+export const dynamicArrayDynamicMembersAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -424,9 +425,9 @@ export const dynamicArrayDynamicMembersAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const dynamicArrayStaticMembersAbi = {
+export const dynamicArrayStaticMembersAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -439,9 +440,9 @@ export const dynamicArrayStaticMembersAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const largeFlatAbi = {
+export const largeFlatAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -486,9 +487,9 @@ export const largeFlatAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const largeNestedAbi = {
+export const largeNestedAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -579,9 +580,9 @@ export const largeNestedAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const nestedTuples = {
+export const nestedTuples: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -668,9 +669,9 @@ export const nestedTuples = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const simpleAbi2 = {
+export const simpleAbi2: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -695,9 +696,9 @@ export const simpleAbi2 = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const fillOrderAbi = {
+export const fillOrderAbi: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -776,4 +777,4 @@ export const fillOrderAbi = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
diff --git a/packages/utils/test/optimizer_abis.ts b/packages/utils/test/optimizer_abis.ts
index ea562e5b5..7cfd7a118 100644
--- a/packages/utils/test/optimizer_abis.ts
+++ b/packages/utils/test/optimizer_abis.ts
@@ -1,6 +1,7 @@
+/* tslint:disable max-file-line-count */
 import { MethodAbi } from 'ethereum-types';
 
-export const duplicateDynamicArraysWithStaticElements = {
+export const duplicateDynamicArraysWithStaticElements: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -17,9 +18,9 @@ export const duplicateDynamicArraysWithStaticElements = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateDynamicArraysWithDynamicElements = {
+export const duplicateDynamicArraysWithDynamicElements: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -36,9 +37,9 @@ export const duplicateDynamicArraysWithDynamicElements = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateStaticArraysWithStaticElements = {
+export const duplicateStaticArraysWithStaticElements: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -55,9 +56,9 @@ export const duplicateStaticArraysWithStaticElements = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateStaticArraysWithDynamicElements = {
+export const duplicateStaticArraysWithDynamicElements: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -74,9 +75,9 @@ export const duplicateStaticArraysWithDynamicElements = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateArrayElements = {
+export const duplicateArrayElements: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -89,9 +90,9 @@ export const duplicateArrayElements = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateTupleFields = {
+export const duplicateTupleFields: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -114,9 +115,9 @@ export const duplicateTupleFields = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateStrings = {
+export const duplicateStrings: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -133,9 +134,9 @@ export const duplicateStrings = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateBytes = {
+export const duplicateBytes: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -152,9 +153,9 @@ export const duplicateBytes = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateTuples = {
+export const duplicateTuples: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -191,9 +192,9 @@ export const duplicateTuples = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateArraysNestedInTuples = {
+export const duplicateArraysNestedInTuples: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -226,9 +227,9 @@ export const duplicateArraysNestedInTuples = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateTuplesNestedInTuples = {
+export const duplicateTuplesNestedInTuples: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -273,9 +274,9 @@ export const duplicateTuplesNestedInTuples = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const duplicateTwoDimensionalArrays = {
+export const duplicateTwoDimensionalArrays: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -292,9 +293,9 @@ export const duplicateTwoDimensionalArrays = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayElementsDuplicatedAsSeparateParameter = {
+export const arrayElementsDuplicatedAsSeparateParameter: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -311,9 +312,9 @@ export const arrayElementsDuplicatedAsSeparateParameter = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const arrayElementsDuplicatedAsTupleFields = {
+export const arrayElementsDuplicatedAsTupleFields: MethodAbi = {
     constant: false,
     inputs: [
         {
@@ -336,4 +337,4 @@ export const arrayElementsDuplicatedAsTupleFields = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
diff --git a/packages/utils/test/return_value_abis.ts b/packages/utils/test/return_value_abis.ts
index 847559dac..ac2124011 100644
--- a/packages/utils/test/return_value_abis.ts
+++ b/packages/utils/test/return_value_abis.ts
@@ -1,6 +1,7 @@
+/* tslint:disable max-file-line-count */
 import { MethodAbi } from 'ethereum-types';
 
-export const noReturnValues = {
+export const noReturnValues: MethodAbi = {
     constant: false,
     inputs: [],
     name: 'simpleFunction',
@@ -8,9 +9,9 @@ export const noReturnValues = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const singleStaticReturnValue = {
+export const singleStaticReturnValue: MethodAbi = {
     constant: false,
     inputs: [],
     name: 'simpleFunction',
@@ -23,9 +24,9 @@ export const singleStaticReturnValue = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const multipleStaticReturnValues = {
+export const multipleStaticReturnValues: MethodAbi = {
     constant: false,
     inputs: [],
     name: 'simpleFunction',
@@ -42,9 +43,9 @@ export const multipleStaticReturnValues = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const singleDynamicReturnValue = {
+export const singleDynamicReturnValue: MethodAbi = {
     constant: false,
     inputs: [],
     name: 'simpleFunction',
@@ -57,9 +58,9 @@ export const singleDynamicReturnValue = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const multipleDynamicReturnValues = {
+export const multipleDynamicReturnValues: MethodAbi = {
     constant: false,
     inputs: [],
     name: 'simpleFunction',
@@ -76,9 +77,9 @@ export const multipleDynamicReturnValues = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
 
-export const mixedStaticAndDynamicReturnValues = {
+export const mixedStaticAndDynamicReturnValues: MethodAbi = {
     constant: false,
     inputs: [],
     name: 'simpleFunction',
@@ -95,4 +96,4 @@ export const mixedStaticAndDynamicReturnValues = {
     payable: false,
     stateMutability: 'nonpayable',
     type: 'function',
-} as MethodAbi;
+};
-- 
cgit v1.2.3


From 29d63cdf976e4cb10b738f7cbb1a57f43c5530ef Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 11:38:47 -0800
Subject: Fixed linter errors in package.json

---
 packages/utils/package.json | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/packages/utils/package.json b/packages/utils/package.json
index 8dc1f0739..1f4d85843 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -33,6 +33,9 @@
         "@types/lodash": "4.14.104",
         "@types/mocha": "^2.2.42",
         "chai": "^4.0.1",
+        "chai-as-promised": "^7.1.0",
+        "chai-bignumber": "^2.0.1",
+        "dirty-chai": "^2.0.1",
         "make-promises-safe": "^1.1.0",
         "mocha": "^4.1.0",
         "npm-run-all": "^4.1.2",
@@ -57,4 +60,4 @@
     "publishConfig": {
         "access": "public"
     }
-}
+}
\ No newline at end of file
-- 
cgit v1.2.3


From 5934e5a57b5897594e22efc9e6ff28841c6951bf Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 11:45:24 -0800
Subject: Renaming some EVM data types for clarity

---
 packages/utils/src/abi_encoder/evm_data_types.ts | 94 ++++++++++++------------
 packages/utils/test/abi_encoder_test.ts          | 58 +++++++--------
 2 files changed, 76 insertions(+), 76 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 24f6051b0..7ad7f403e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -9,7 +9,7 @@ import * as Constants from './constants';
 import { DataType, DataTypeFactory, DependentDataType, MemberDataType, PayloadDataType } from './data_type';
 
 export interface DataTypeStaticInterface {
-    matchGrammar: (type: string) => boolean;
+    matchType: (type: string) => boolean;
     encodeValue: (value: any) => Buffer;
     decodeValue: (rawCalldata: RawCalldata) => any;
 }
@@ -21,13 +21,13 @@ export class Address extends PayloadDataType {
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES - Address._ADDRESS_SIZE_IN_BYTES;
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return type === 'address';
     }
 
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance(), Address._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Address.matchGrammar(dataItem.type)) {
+        if (!Address.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
         }
     }
@@ -59,13 +59,13 @@ export class Address extends PayloadDataType {
 export class Bool extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return type === 'bool';
     }
 
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance(), Bool._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bool.matchGrammar(dataItem.type)) {
+        if (!Bool.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
         }
     }
@@ -184,7 +184,7 @@ export class Int extends Number {
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return Int._matcher.test(type);
     }
 
@@ -210,7 +210,7 @@ export class UInt extends Number {
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return UInt._matcher.test(type);
     }
 
@@ -231,7 +231,7 @@ export class UInt extends Number {
     }
 }
 
-export class Byte extends PayloadDataType {
+export class StaticBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _matcher = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
@@ -240,17 +240,17 @@ export class Byte extends PayloadDataType {
     private static readonly _DEFAULT_WIDTH = 1;
     private readonly _width: number;
 
-    public static matchGrammar(type: string): boolean {
-        return Byte._matcher.test(type);
+    public static matchType(type: string): boolean {
+        return StaticBytes._matcher.test(type);
     }
 
     public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Byte._SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = Byte._matcher.exec(dataItem.type);
-        if (!Byte.matchGrammar(dataItem.type)) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), StaticBytes._SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = StaticBytes._matcher.exec(dataItem.type);
+        if (!StaticBytes.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
         }
-        this._width = (matches !== null && matches.length === 3 && matches[2] !== undefined) ? parseInt(matches[2], Constants.DEC_BASE) : Byte._DEFAULT_WIDTH;
+        this._width = (matches !== null && matches.length === 3 && matches[2] !== undefined) ? parseInt(matches[2], Constants.DEC_BASE) : StaticBytes._DEFAULT_WIDTH;
     }
 
     public getSignature(): string {
@@ -289,17 +289,17 @@ export class Byte extends PayloadDataType {
     }
 }
 
-export class Bytes extends PayloadDataType {
+export class DynamicBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return type === 'bytes';
     }
 
     public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bytes._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bytes.matchGrammar(dataItem.type)) {
-            throw new Error(`Tried to instantiate Bytes with bad input: ${dataItem}`);
+        super(dataItem, EvmDataTypeFactory.getInstance(), DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!DynamicBytes.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate DynamicBytes with bad input: ${dataItem}`);
         }
     }
 
@@ -313,8 +313,8 @@ export class Bytes extends PayloadDataType {
         }
 
         const wordsForValue = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
-        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedBytesForValue);
+        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedDynamicBytesForValue);
         const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), Constants.EVM_WORD_WIDTH_IN_BYTES);
         const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
         return encodedValueBuf;
@@ -336,24 +336,24 @@ export class Bytes extends PayloadDataType {
     }
 }
 
-export class SolString extends PayloadDataType {
+export class String extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return type === 'string';
     }
 
     public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), SolString._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!SolString.matchGrammar(dataItem.type)) {
+        super(dataItem, EvmDataTypeFactory.getInstance(), String._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!String.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
         }
     }
 
     public encodeValue(value: string): Buffer {
         const wordsForValue = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
-        const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedBytesForValue);
+        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedDynamicBytesForValue);
         const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), Constants.EVM_WORD_WIDTH_IN_BYTES);
         const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
         return encodedValueBuf;
@@ -390,13 +390,13 @@ export class Pointer extends DependentDataType {
 export class Tuple extends MemberDataType {
     private readonly _tupleSignature: string;
 
-    public static matchGrammar(type: string): boolean {
+    public static matchType(type: string): boolean {
         return type === 'tuple';
     }
 
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
-        if (!Tuple.matchGrammar(dataItem.type)) {
+        if (!Tuple.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
         }
         this._tupleSignature = this._computeSignatureOfMembers();
@@ -407,18 +407,18 @@ export class Tuple extends MemberDataType {
     }
 }
 
-export class SolArray extends MemberDataType {
+export class Array extends MemberDataType {
     private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
     private readonly _arraySignature: string;
     private readonly _elementType: string;
 
-    public static matchGrammar(type: string): boolean {
-        return SolArray._matcher.test(type);
+    public static matchType(type: string): boolean {
+        return Array._matcher.test(type);
     }
 
     public constructor(dataItem: DataItem) {
         // Sanity check
-        const matches = SolArray._matcher.exec(dataItem.type);
+        const matches = Array._matcher.exec(dataItem.type);
         if (matches === null || matches.length !== 3) {
             throw new Error(`Could not parse array: ${dataItem.type}`);
         } else if (matches[1] === undefined) {
@@ -473,7 +473,7 @@ export class Method extends MemberDataType {
         this.selector = this._methodSelector = this._computeSelector();
         this._returnDataTypes = [];
         this._returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
-        const dummy = new Byte({ type: 'byte', name: 'DUMMY' }); // @TODO TMP
+        const dummy = new StaticBytes({ type: 'byte', name: 'DUMMY' }); // @TODO TMP
         _.each(abi.outputs, (dataItem: DataItem) => {
             this._returnDataTypes.push(this.getFactory().create(dataItem, dummy));
         });
@@ -543,24 +543,24 @@ export class EvmDataTypeFactory implements DataTypeFactory {
     }
 
     public mapDataItemToDataType(dataItem: DataItem): DataType {
-        if (SolArray.matchGrammar(dataItem.type)) {
-            return new SolArray(dataItem);
-        } else if (Address.matchGrammar(dataItem.type)) {
+        if (Array.matchType(dataItem.type)) {
+            return new Array(dataItem);
+        } else if (Address.matchType(dataItem.type)) {
             return new Address(dataItem);
-        } else if (Bool.matchGrammar(dataItem.type)) {
+        } else if (Bool.matchType(dataItem.type)) {
             return new Bool(dataItem);
-        } else if (Int.matchGrammar(dataItem.type)) {
+        } else if (Int.matchType(dataItem.type)) {
             return new Int(dataItem);
-        } else if (UInt.matchGrammar(dataItem.type)) {
+        } else if (UInt.matchType(dataItem.type)) {
             return new UInt(dataItem);
-        } else if (Byte.matchGrammar(dataItem.type)) {
-            return new Byte(dataItem);
-        } else if (Tuple.matchGrammar(dataItem.type)) {
+        } else if (StaticBytes.matchType(dataItem.type)) {
+            return new StaticBytes(dataItem);
+        } else if (Tuple.matchType(dataItem.type)) {
             return new Tuple(dataItem);
-        } else if (Bytes.matchGrammar(dataItem.type)) {
-            return new Bytes(dataItem);
-        } else if (SolString.matchGrammar(dataItem.type)) {
-            return new SolString(dataItem);
+        } else if (DynamicBytes.matchType(dataItem.type)) {
+            return new DynamicBytes(dataItem);
+        } else if (String.matchType(dataItem.type)) {
+            return new String(dataItem);
         }
         // @TODO: Implement Fixed/UFixed types
         throw new Error(`Unrecognized data type: '${dataItem.type}'`);
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
index e99528b06..35eb8d0a9 100644
--- a/packages/utils/test/abi_encoder_test.ts
+++ b/packages/utils/test/abi_encoder_test.ts
@@ -772,7 +772,7 @@ describe.only('ABI Encoder', () => {
         it('Fixed size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[2]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = [new BigNumber(5), new BigNumber(6)];
             // Encode Args and validate result
@@ -789,7 +789,7 @@ describe.only('ABI Encoder', () => {
         it('Dynamic size; Static elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'int[]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = [new BigNumber(5), new BigNumber(6)];
             // Encode Args and validate result
@@ -806,7 +806,7 @@ describe.only('ABI Encoder', () => {
         it('Fixed size; Dynamic elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[2]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = ['Hello', 'world'];
             // Encode Args and validate result
@@ -823,7 +823,7 @@ describe.only('ABI Encoder', () => {
         it('Dynamic size; Dynamic elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = ['Hello', 'world'];
             // Encode Args and validate result
@@ -840,7 +840,7 @@ describe.only('ABI Encoder', () => {
         it('Dynamic Size; Multidimensional; Dynamic Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'bytes[][]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const array1 = ['0x01020304', '0x05060708', '0x09101112'];
             const array2 = ['0x10111213', '0x14151617'];
@@ -860,7 +860,7 @@ describe.only('ABI Encoder', () => {
         it('Dynamic Size; Multidimensional; Static Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'bytes4[][]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const array1 = ['0x01020304', '0x05060708', '0x09101112'];
             const array2 = ['0x10111213', '0x14151617'];
@@ -880,7 +880,7 @@ describe.only('ABI Encoder', () => {
         it('Static Size; Multidimensional; Static Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'bytes4[3][2]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const array1 = ['0x01020304', '0x05060708', '0x09101112'];
             const array2 = ['0x10111213', '0x14151617', '0x18192021'];
@@ -899,7 +899,7 @@ describe.only('ABI Encoder', () => {
         it('Static Size; Multidimensional; Dynamic Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'bytes[3][2]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const array1 = ['0x01020304', '0x05060708', '0x09101112'];
             const array2 = ['0x10111213', '0x14151617', '0x18192021'];
@@ -918,7 +918,7 @@ describe.only('ABI Encoder', () => {
         it('Static size; Too Few Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[3]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = ['Hello', 'world'];
             // Encode Args and validate result
@@ -929,7 +929,7 @@ describe.only('ABI Encoder', () => {
         it('Static size; Too Many Elements', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'string[1]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = ['Hello', 'world'];
             // Encode Args and validate result
@@ -940,7 +940,7 @@ describe.only('ABI Encoder', () => {
         it('Element Type Mismatch', async () => {
             // Create DataType object
             const testDataItem = { name: 'testArray', type: 'uint[]' };
-            const dataType = new AbiEncoder.SolArray(testDataItem);
+            const dataType = new AbiEncoder.Array(testDataItem);
             // Construct args to be encoded
             const args = [new BigNumber(1), 'Bad Argument'];
             // Encode Args and validate result
@@ -1563,7 +1563,7 @@ describe.only('ABI Encoder', () => {
         it('Single Byte (byte)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Byte', type: 'byte' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x05';
             // Encode Args and validate result
@@ -1579,7 +1579,7 @@ describe.only('ABI Encoder', () => {
         it('Single Byte (bytes1)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes1', type: 'bytes1' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x05';
             // Encode Args and validate result
@@ -1595,7 +1595,7 @@ describe.only('ABI Encoder', () => {
         it('4 Bytes (bytes4)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x00010203';
             // Encode Args and validate result
@@ -1611,7 +1611,7 @@ describe.only('ABI Encoder', () => {
         it('4 Bytes (bytes4); Encoder must pad input', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18';
@@ -1629,7 +1629,7 @@ describe.only('ABI Encoder', () => {
         it('32 Bytes (bytes32)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x0001020304050607080911121314151617181920212223242526272829303132';
             // Encode Args and validate result
@@ -1645,7 +1645,7 @@ describe.only('ABI Encoder', () => {
         it('32 Bytes (bytes32); Encoder must pad input', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18bf61';
@@ -1663,7 +1663,7 @@ describe.only('ABI Encoder', () => {
         it('Should throw when pass in too many bytes (bytes4)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x0102030405';
             // Encode Args and validate result
@@ -1676,7 +1676,7 @@ describe.only('ABI Encoder', () => {
         it('Should throw when pass in too many bytes (bytes32)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x010203040506070809101112131415161718192021222324252627282930313233';
             // Encode Args and validate result
@@ -1689,7 +1689,7 @@ describe.only('ABI Encoder', () => {
         it('Should throw when pass in bad hex (no 0x prefix)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0102030405060708091011121314151617181920212223242526272829303132';
             // Encode Args and validate result
@@ -1700,7 +1700,7 @@ describe.only('ABI Encoder', () => {
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.Byte(testDataItem);
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x010';
             // Encode Args and validate result
@@ -1714,7 +1714,7 @@ describe.only('ABI Encoder', () => {
         it('Fits into one EVM word', async () => {
             // Create DataType object
             const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.Bytes(testDataItem);
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18bf61';
@@ -1732,7 +1732,7 @@ describe.only('ABI Encoder', () => {
         it('Spans multiple EVM words', async () => {
             // Create DataType object
             const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.Bytes(testDataItem);
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const bytesLength = 40;
@@ -1751,7 +1751,7 @@ describe.only('ABI Encoder', () => {
         it('Input as Buffer', async () => {
             // Create DataType object
             const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.Bytes(testDataItem);
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18bf61';
@@ -1770,7 +1770,7 @@ describe.only('ABI Encoder', () => {
         it('Should throw when pass in bad hex (no 0x prefix)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.Bytes(testDataItem);
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
             // Construct args to be encoded
             const args = '01';
             // Encode Args and validate result
@@ -1781,7 +1781,7 @@ describe.only('ABI Encoder', () => {
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
             // Create DataType object
             const testDataItem = { name: 'Static Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.Bytes(testDataItem);
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
             // Construct args to be encoded
             const args = '0x010';
             // Encode Args and validate result
@@ -1795,7 +1795,7 @@ describe.only('ABI Encoder', () => {
         it('Fits into one EVM word', async () => {
             // Create DataType object
             const testDataItem = { name: 'String', type: 'string' };
-            const dataType = new AbiEncoder.SolString(testDataItem);
+            const dataType = new AbiEncoder.String(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = 'five';
@@ -1813,7 +1813,7 @@ describe.only('ABI Encoder', () => {
         it('Spans multiple EVM words', async () => {
             // Create DataType object
             const testDataItem = { name: 'String', type: 'string' };
-            const dataType = new AbiEncoder.SolString(testDataItem);
+            const dataType = new AbiEncoder.String(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const bytesLength = 40;
@@ -1832,7 +1832,7 @@ describe.only('ABI Encoder', () => {
         it('String that begins with 0x prefix', async () => {
             // Create DataType object
             const testDataItem = { name: 'String', type: 'string' };
-            const dataType = new AbiEncoder.SolString(testDataItem);
+            const dataType = new AbiEncoder.String(testDataItem);
             // Construct args to be encoded
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const strLength = 40;
-- 
cgit v1.2.3


From e6ab6f38bacdec90c960ff1db4781d161b1f4103 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 12:58:49 -0800
Subject: Split EVM data types and factory into separate files

---
 packages/utils/src/abi_encoder/calldata.ts         |   1 -
 packages/utils/src/abi_encoder/data_type.ts        |  11 +-
 .../utils/src/abi_encoder/evm_data_type_factory.ts | 124 +++++
 packages/utils/src/abi_encoder/evm_data_types.ts   | 584 ---------------------
 .../src/abi_encoder/evm_data_types/address.ts      |  51 ++
 .../utils/src/abi_encoder/evm_data_types/array.ts  |  55 ++
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |  50 ++
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    |  58 ++
 .../utils/src/abi_encoder/evm_data_types/index.ts  |  11 +
 .../utils/src/abi_encoder/evm_data_types/int.ts    |  33 ++
 .../utils/src/abi_encoder/evm_data_types/method.ts |  90 ++++
 .../utils/src/abi_encoder/evm_data_types/number.ts | 100 ++++
 .../src/abi_encoder/evm_data_types/pointer.ts      |  15 +
 .../src/abi_encoder/evm_data_types/static_bytes.ts |  68 +++
 .../utils/src/abi_encoder/evm_data_types/string.ts |  47 ++
 .../utils/src/abi_encoder/evm_data_types/tuple.ts  |  23 +
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |  33 ++
 packages/utils/src/abi_encoder/index.ts            |   2 +-
 18 files changed, 769 insertions(+), 587 deletions(-)
 create mode 100644 packages/utils/src/abi_encoder/evm_data_type_factory.ts
 delete mode 100644 packages/utils/src/abi_encoder/evm_data_types.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/address.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/array.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/bool.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/index.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/int.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/method.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/number.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/pointer.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/string.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/tuple.ts
 create mode 100644 packages/utils/src/abi_encoder/evm_data_types/uint.ts

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 994b0fb81..d108ef0a7 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -1,4 +1,3 @@
-
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index ce7b11ef6..9890619e5 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -22,6 +22,12 @@ export interface DataTypeFactory {
     mapDataItemToDataType: (dataItem: DataItem) => DataType;
 }
 
+export interface DataTypeStaticInterface {
+    matchType: (type: string) => boolean;
+    encodeValue: (value: any) => Buffer;
+    decodeValue: (rawCalldata: RawCalldata) => any;
+}
+
 export abstract class DataType {
     private static readonly _DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
     private static readonly _DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
@@ -250,7 +256,10 @@ export abstract class MemberDataType extends DataType {
         if (this._isArray && this._arrayLength === undefined) {
             [members] = this._createMembersWithLength(this.getDataItem(), value.length);
 
-            const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
+            const lenBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
+                Constants.EVM_WORD_WIDTH_IN_BYTES,
+            );
             methodBlock.setHeader(lenBuf);
         }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
new file mode 100644
index 000000000..0f8dfb4a3
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -0,0 +1,124 @@
+/* tslint:disable prefer-function-over-method */
+/* tslint:disable max-classes-per-file */
+/* tslint:disable no-construct */
+import { DataItem, MethodAbi } from 'ethereum-types';
+
+import { DataType, DataTypeFactory } from './data_type';
+import * as Impl from './evm_data_types';
+
+export class Address extends Impl.Address {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class Bool extends Impl.Bool {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class Int extends Impl.Int {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class UInt extends Impl.UInt {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class StaticBytes extends Impl.StaticBytes {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class DynamicBytes extends Impl.DynamicBytes {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class String extends Impl.String {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class Pointer extends Impl.Pointer {
+    public constructor(destDataType: DataType, parentDataType: DataType) {
+        super(destDataType, parentDataType, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class Tuple extends Impl.Tuple {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class Array extends Impl.Array {
+    public constructor(dataItem: DataItem) {
+        super(dataItem, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class Method extends Impl.Method {
+    public constructor(abi: MethodAbi) {
+        super(abi, EvmDataTypeFactory.getInstance());
+    }
+}
+
+export class EvmDataTypeFactory implements DataTypeFactory {
+    private static _instance: DataTypeFactory;
+
+    public static getInstance(): DataTypeFactory {
+        if (!EvmDataTypeFactory._instance) {
+            EvmDataTypeFactory._instance = new EvmDataTypeFactory();
+        }
+        return EvmDataTypeFactory._instance;
+    }
+
+    public mapDataItemToDataType(dataItem: DataItem): DataType {
+        if (Array.matchType(dataItem.type)) {
+            return new Array(dataItem);
+        } else if (Address.matchType(dataItem.type)) {
+            return new Address(dataItem);
+        } else if (Bool.matchType(dataItem.type)) {
+            return new Bool(dataItem);
+        } else if (Int.matchType(dataItem.type)) {
+            return new Int(dataItem);
+        } else if (UInt.matchType(dataItem.type)) {
+            return new UInt(dataItem);
+        } else if (StaticBytes.matchType(dataItem.type)) {
+            return new StaticBytes(dataItem);
+        } else if (Tuple.matchType(dataItem.type)) {
+            return new Tuple(dataItem);
+        } else if (DynamicBytes.matchType(dataItem.type)) {
+            return new DynamicBytes(dataItem);
+        } else if (String.matchType(dataItem.type)) {
+            return new String(dataItem);
+        }
+        // @TODO: Implement Fixed/UFixed types
+        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+    }
+
+    public create(dataItem: DataItem, parentDataType?: DataType): DataType {
+        const dataType = this.mapDataItemToDataType(dataItem);
+        if (dataType.isStatic()) {
+            return dataType;
+        }
+
+        if (parentDataType === undefined) {
+            // @Todo -- will this work for return values?
+            throw new Error(`Trying to create a pointer`);
+        }
+        const pointer = new Pointer(dataType, parentDataType);
+        return pointer;
+    }
+
+    private constructor() { }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
deleted file mode 100644
index 7ad7f403e..000000000
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ /dev/null
@@ -1,584 +0,0 @@
-import { DataItem, MethodAbi } from 'ethereum-types';
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-import { BigNumber } from '../configured_bignumber';
-
-import { DecodingRules, EncodingRules, RawCalldata } from './calldata';
-import * as Constants from './constants';
-import { DataType, DataTypeFactory, DependentDataType, MemberDataType, PayloadDataType } from './data_type';
-
-export interface DataTypeStaticInterface {
-    matchType: (type: string) => boolean;
-    encodeValue: (value: any) => Buffer;
-    decodeValue: (rawCalldata: RawCalldata) => any;
-}
-
-export class Address extends PayloadDataType {
-    public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
-    public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes';
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
-    private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES - Address._ADDRESS_SIZE_IN_BYTES;
-
-    public static matchType(type: string): boolean {
-        return type === 'address';
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Address._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Address.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
-        }
-    }
-
-    public getSignature(): string {
-        return 'address';
-    }
-
-    public encodeValue(value: string): Buffer {
-        if (!value.startsWith('0x')) {
-            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
-        }
-        const valueAsBuffer = ethUtil.toBuffer(value);
-        if (valueAsBuffer.byteLength !== Address._ADDRESS_SIZE_IN_BYTES) {
-            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
-        }
-        const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, Constants.EVM_WORD_WIDTH_IN_BYTES);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(Address._DECODED_ADDRESS_OFFSET_IN_BYTES);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
-    }
-}
-
-export class Bool extends PayloadDataType {
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-
-    public static matchType(type: string): boolean {
-        return type === 'bool';
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Bool._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bool.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
-        }
-    }
-
-    public getSignature(): string {
-        return 'bool';
-    }
-
-    public encodeValue(value: boolean): Buffer {
-        const encodedValue = value ? '0x1' : '0x0';
-        const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(encodedValue), Constants.EVM_WORD_WIDTH_IN_BYTES);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): boolean {
-        const valueBuf = calldata.popWord();
-        const valueHex = ethUtil.bufferToHex(valueBuf);
-        const valueNumber = new BigNumber(valueHex, 16);
-        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
-            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
-        }
-        /* tslint:disable boolean-naming */
-        const value: boolean = valueNumber.equals(0) ? false : true;
-        /* tslint:enable boolean-naming */
-        return value;
-    }
-}
-
-abstract class Number extends PayloadDataType {
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    private static readonly _MAX_WIDTH: number = 256;
-    private static readonly _DEFAULT_WIDTH: number = Number._MAX_WIDTH;
-    protected _width: number;
-
-    constructor(dataItem: DataItem, matcher: RegExp) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), Number._SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = matcher.exec(dataItem.type);
-        if (matches === null) {
-            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
-        }
-        this._width = (matches !== null && matches.length === 2 && matches[1] !== undefined) ?
-            parseInt(matches[1], Constants.DEC_BASE) :
-            this._width = Number._DEFAULT_WIDTH;
-    }
-
-    public encodeValue(value_: BigNumber | string | number): Buffer {
-        const value = new BigNumber(value_, 10);
-        if (value.greaterThan(this.getMaxValue())) {
-            throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`);
-        } else if (value.lessThan(this.getMinValue())) {
-            throw new Error(`Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`);
-        }
-
-        let valueBuf: Buffer;
-        if (value.greaterThanOrEqualTo(0)) {
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
-        } else {
-            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
-            // Step 1/3: Convert value to positive binary string
-            const binBase = 2;
-            const valueBin = value.times(-1).toString(binBase);
-
-            // Step 2/3: Invert binary value
-            let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
-            _.each(valueBin, (bit: string) => {
-                invertedValueBin += bit === '1' ? '0' : '1';
-            });
-            const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-            // Step 3/3: Add 1 to inverted value
-            // The result is the two's-complement represent of the input value.
-            const negativeValue = invertedValue.plus(1);
-
-            // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${negativeValue.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
-        }
-
-        return valueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): BigNumber {
-        const paddedValueBuf = calldata.popWord();
-        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
-        let value = new BigNumber(paddedValueHex, 16);
-        if (this instanceof Int) {
-            // Check if we're negative
-            const valueBin = value.toString(Constants.BIN_BASE);
-            if (valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1')) {
-                // Negative
-                // Step 1/3: Invert binary value
-                let invertedValueBin = '';
-                _.each(valueBin, (bit: string) => {
-                    invertedValueBin += bit === '1' ? '0' : '1';
-                });
-                const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
-
-                // Step 2/3: Add 1 to inverted value
-                // The result is the two's-complement represent of the input value.
-                const positiveValue = invertedValue.plus(1);
-
-                // Step 3/3: Invert positive value
-                const negativeValue = positiveValue.times(-1);
-                value = negativeValue;
-            }
-        }
-
-        return value;
-    }
-
-    public abstract getMaxValue(): BigNumber;
-    public abstract getMinValue(): BigNumber;
-}
-
-export class Int extends Number {
-    private static readonly _matcher = RegExp(
-        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    public static matchType(type: string): boolean {
-        return Int._matcher.test(type);
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, Int._matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this._width - 1).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(2).toPower(this._width - 1).times(-1);
-    }
-
-    public getSignature(): string {
-        return `int${this._width}`;
-    }
-}
-
-export class UInt extends Number {
-    private static readonly _matcher = RegExp(
-        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
-    );
-
-    public static matchType(type: string): boolean {
-        return UInt._matcher.test(type);
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, UInt._matcher);
-    }
-
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this._width).sub(1);
-    }
-
-    public getMinValue(): BigNumber {
-        return new BigNumber(0);
-    }
-
-    public getSignature(): string {
-        return `uint${this._width}`;
-    }
-}
-
-export class StaticBytes extends PayloadDataType {
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    private static readonly _matcher = RegExp(
-        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
-    );
-
-    private static readonly _DEFAULT_WIDTH = 1;
-    private readonly _width: number;
-
-    public static matchType(type: string): boolean {
-        return StaticBytes._matcher.test(type);
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), StaticBytes._SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = StaticBytes._matcher.exec(dataItem.type);
-        if (!StaticBytes.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
-        }
-        this._width = (matches !== null && matches.length === 3 && matches[2] !== undefined) ? parseInt(matches[2], Constants.DEC_BASE) : StaticBytes._DEFAULT_WIDTH;
-    }
-
-    public getSignature(): string {
-        // Note that `byte` reduces to `bytes1`
-        return `bytes${this._width}`;
-    }
-
-    public encodeValue(value: string | Buffer): Buffer {
-        // Sanity check if string
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
-        }
-        // Convert value into a buffer and do bounds checking
-        const valueBuf = ethUtil.toBuffer(value);
-        if (valueBuf.byteLength > this._width) {
-            throw new Error(
-                `Tried to assign ${value} (${
-                valueBuf.byteLength
-                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
-            );
-        } else if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        // Store value as hex
-        const evmWordWidth = 32;
-        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
-        return paddedValue;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(0, this._width);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
-    }
-}
-
-export class DynamicBytes extends PayloadDataType {
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-
-    public static matchType(type: string): boolean {
-        return type === 'bytes';
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!DynamicBytes.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate DynamicBytes with bad input: ${dataItem}`);
-        }
-    }
-
-    public encodeValue(value: string | Buffer): Buffer {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '${value}'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        const wordsForValue = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
-        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedDynamicBytesForValue);
-        const paddedLengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(valueBuf.byteLength), Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, Constants.HEX_BASE);
-        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const decodedValue = ethUtil.bufferToHex(valueBuf);
-        return decodedValue;
-    }
-
-    public getSignature(): string {
-        return 'bytes';
-    }
-}
-
-export class String extends PayloadDataType {
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
-
-    public static matchType(type: string): boolean {
-        return type === 'string';
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance(), String._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!String.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
-        }
-    }
-
-    public encodeValue(value: string): Buffer {
-        const wordsForValue = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
-        const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedDynamicBytesForValue);
-        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
-        return encodedValueBuf;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, Constants.HEX_BASE);
-        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const value = valueBuf.toString('ascii');
-        return value;
-    }
-
-    public getSignature(): string {
-        return 'string';
-    }
-}
-
-export class Pointer extends DependentDataType {
-    constructor(destDataType: DataType, parentDataType: DataType) {
-        const destDataItem = destDataType.getDataItem();
-        const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` };
-        super(dataItem, EvmDataTypeFactory.getInstance(), destDataType, parentDataType);
-    }
-
-    public getSignature(): string {
-        return this._dependency.getSignature();
-    }
-}
-
-export class Tuple extends MemberDataType {
-    private readonly _tupleSignature: string;
-
-    public static matchType(type: string): boolean {
-        return type === 'tuple';
-    }
-
-    public constructor(dataItem: DataItem) {
-        super(dataItem, EvmDataTypeFactory.getInstance());
-        if (!Tuple.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
-        }
-        this._tupleSignature = this._computeSignatureOfMembers();
-    }
-
-    public getSignature(): string {
-        return this._tupleSignature;
-    }
-}
-
-export class Array extends MemberDataType {
-    private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
-    private readonly _arraySignature: string;
-    private readonly _elementType: string;
-
-    public static matchType(type: string): boolean {
-        return Array._matcher.test(type);
-    }
-
-    public constructor(dataItem: DataItem) {
-        // Sanity check
-        const matches = Array._matcher.exec(dataItem.type);
-        if (matches === null || matches.length !== 3) {
-            throw new Error(`Could not parse array: ${dataItem.type}`);
-        } else if (matches[1] === undefined) {
-            throw new Error(`Could not parse array type: ${dataItem.type}`);
-        } else if (matches[2] === undefined) {
-            throw new Error(`Could not parse array length: ${dataItem.type}`);
-        }
-
-        const isArray = true;
-        const arrayElementType = matches[1];
-        const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], Constants.DEC_BASE);
-        super(dataItem, EvmDataTypeFactory.getInstance(), isArray, arrayLength, arrayElementType);
-        this._elementType = arrayElementType;
-        this._arraySignature = this._computeSignature();
-    }
-
-    public getSignature(): string {
-        return this._arraySignature;
-    }
-
-    private _computeSignature(): string {
-        const dataItem: DataItem = {
-            type: this._elementType,
-            name: 'N/A',
-        };
-        const components = this.getDataItem().components;
-        if (components !== undefined) {
-            dataItem.components = components;
-        }
-        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
-        const type = elementDataType.getSignature();
-        if (this._arrayLength === undefined) {
-            return `${type}[]`;
-        } else {
-            return `${type}[${this._arrayLength}]`;
-        }
-    }
-}
-
-export class Method extends MemberDataType {
-    // TMP
-    public selector: string;
-
-    private readonly _methodSignature: string;
-    private readonly _methodSelector: string;
-    private readonly _returnDataTypes: DataType[];
-    private readonly _returnDataItem: DataItem;
-
-    public constructor(abi: MethodAbi) {
-        super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance());
-        this._methodSignature = this._computeSignature();
-        this.selector = this._methodSelector = this._computeSelector();
-        this._returnDataTypes = [];
-        this._returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
-        const dummy = new StaticBytes({ type: 'byte', name: 'DUMMY' }); // @TODO TMP
-        _.each(abi.outputs, (dataItem: DataItem) => {
-            this._returnDataTypes.push(this.getFactory().create(dataItem, dummy));
-        });
-    }
-
-    public encode(value: any, rules?: EncodingRules): string {
-        const calldata = super.encode(value, rules, this.selector);
-        return calldata;
-    }
-
-    public decode(calldata: string, rules?: DecodingRules): any[] | object {
-        if (!calldata.startsWith(this.selector)) {
-            throw new Error(
-                `Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`,
-            );
-        }
-        const hasSelector = true;
-        const value = super.decode(calldata, rules, hasSelector);
-        return value;
-    }
-
-    public encodeReturnValues(value: any, rules?: EncodingRules): string {
-        const returnDataType = new Tuple(this._returnDataItem);
-        const returndata = returnDataType.encode(value, rules);
-        return returndata;
-    }
-
-    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
-        const returnValues: any[] = [];
-        const rules_: DecodingRules = rules ? rules : { structsAsObjects: false };
-        const rawReturnData = new RawCalldata(returndata, false);
-        _.each(this._returnDataTypes, (dataType: DataType) => {
-            returnValues.push(dataType.generateValue(rawReturnData, rules_));
-        });
-        return returnValues;
-    }
-
-    public getSignature(): string {
-        return this._methodSignature;
-    }
-
-    public getSelector(): string {
-        return this._methodSelector;
-    }
-
-    private _computeSignature(): string {
-        const memberSignature = this._computeSignatureOfMembers();
-        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
-        return methodSignature;
-    }
-
-    private _computeSelector(): string {
-        const signature = this._computeSignature();
-        const selector = ethUtil.bufferToHex(ethUtil.toBuffer(ethUtil.sha3(signature).slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES)));
-        return selector;
-    }
-}
-
-export class EvmDataTypeFactory implements DataTypeFactory {
-    private static _instance: DataTypeFactory;
-
-    public static getInstance(): DataTypeFactory {
-        if (!EvmDataTypeFactory._instance) {
-            EvmDataTypeFactory._instance = new EvmDataTypeFactory();
-        }
-        return EvmDataTypeFactory._instance;
-    }
-
-    public mapDataItemToDataType(dataItem: DataItem): DataType {
-        if (Array.matchType(dataItem.type)) {
-            return new Array(dataItem);
-        } else if (Address.matchType(dataItem.type)) {
-            return new Address(dataItem);
-        } else if (Bool.matchType(dataItem.type)) {
-            return new Bool(dataItem);
-        } else if (Int.matchType(dataItem.type)) {
-            return new Int(dataItem);
-        } else if (UInt.matchType(dataItem.type)) {
-            return new UInt(dataItem);
-        } else if (StaticBytes.matchType(dataItem.type)) {
-            return new StaticBytes(dataItem);
-        } else if (Tuple.matchType(dataItem.type)) {
-            return new Tuple(dataItem);
-        } else if (DynamicBytes.matchType(dataItem.type)) {
-            return new DynamicBytes(dataItem);
-        } else if (String.matchType(dataItem.type)) {
-            return new String(dataItem);
-        }
-        // @TODO: Implement Fixed/UFixed types
-        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-    }
-
-    public create(dataItem: DataItem, parentDataType?: DataType): DataType {
-        const dataType = this.mapDataItemToDataType(dataItem);
-        if (dataType.isStatic()) {
-            return dataType;
-        }
-
-        if (parentDataType === undefined) {
-            // @Todo -- will this work for return values?
-            throw new Error(`Trying to create a pointer`);
-        }
-        const pointer = new Pointer(dataType, parentDataType);
-        return pointer;
-    }
-
-    private constructor() { }
-}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
new file mode 100644
index 000000000..4bd992cab
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -0,0 +1,51 @@
+/* tslint:disable prefer-function-over-method */
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataTypeFactory, PayloadDataType } from '../data_type';
+
+export class Address extends PayloadDataType {
+    public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
+    public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes';
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
+    private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
+        Address._ADDRESS_SIZE_IN_BYTES;
+
+    public static matchType(type: string): boolean {
+        return type === 'address';
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory, Address._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Address.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'address';
+    }
+
+    public encodeValue(value: string): Buffer {
+        if (!value.startsWith('0x')) {
+            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+        }
+        const valueAsBuffer = ethUtil.toBuffer(value);
+        if (valueAsBuffer.byteLength !== Address._ADDRESS_SIZE_IN_BYTES) {
+            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
+        }
+        const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(Address._DECODED_ADDRESS_OFFSET_IN_BYTES);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
new file mode 100644
index 000000000..707af7c7e
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -0,0 +1,55 @@
+import { DataItem } from 'ethereum-types';
+
+import * as Constants from '../constants';
+import { DataTypeFactory, MemberDataType } from '../data_type';
+
+export class Array extends MemberDataType {
+    private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    private readonly _arraySignature: string;
+    private readonly _elementType: string;
+
+    public static matchType(type: string): boolean {
+        return Array._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        // Sanity check
+        const matches = Array._matcher.exec(dataItem.type);
+        if (matches === null || matches.length !== 3) {
+            throw new Error(`Could not parse array: ${dataItem.type}`);
+        } else if (matches[1] === undefined) {
+            throw new Error(`Could not parse array type: ${dataItem.type}`);
+        } else if (matches[2] === undefined) {
+            throw new Error(`Could not parse array length: ${dataItem.type}`);
+        }
+
+        const isArray = true;
+        const arrayElementType = matches[1];
+        const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], Constants.DEC_BASE);
+        super(dataItem, dataTypeFactory, isArray, arrayLength, arrayElementType);
+        this._elementType = arrayElementType;
+        this._arraySignature = this._computeSignature();
+    }
+
+    public getSignature(): string {
+        return this._arraySignature;
+    }
+
+    private _computeSignature(): string {
+        const dataItem: DataItem = {
+            type: this._elementType,
+            name: 'N/A',
+        };
+        const components = this.getDataItem().components;
+        if (components !== undefined) {
+            dataItem.components = components;
+        }
+        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
+        const type = elementDataType.getSignature();
+        if (this._arrayLength === undefined) {
+            return `${type}[]`;
+        } else {
+            return `${type}[${this._arrayLength}]`;
+        }
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
new file mode 100644
index 000000000..aee2727c7
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -0,0 +1,50 @@
+/* tslint:disable prefer-function-over-method */
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../../configured_bignumber';
+import { RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataTypeFactory, PayloadDataType } from '../data_type';
+
+export class Bool extends PayloadDataType {
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+    public static matchType(type: string): boolean {
+        return type === 'bool';
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory, Bool._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Bool.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
+        }
+    }
+
+    public getSignature(): string {
+        return 'bool';
+    }
+
+    public encodeValue(value: boolean): Buffer {
+        const encodedValue = value ? '0x1' : '0x0';
+        const encodedValueBuf = ethUtil.setLengthLeft(
+            ethUtil.toBuffer(encodedValue),
+            Constants.EVM_WORD_WIDTH_IN_BYTES,
+        );
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): boolean {
+        const valueBuf = calldata.popWord();
+        const valueHex = ethUtil.bufferToHex(valueBuf);
+        const valueNumber = new BigNumber(valueHex, Constants.HEX_BASE);
+        if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
+            throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
+        }
+        /* tslint:disable boolean-naming */
+        const value: boolean = valueNumber.equals(0) ? false : true;
+        /* tslint:enable boolean-naming */
+        return value;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
new file mode 100644
index 000000000..51165881a
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -0,0 +1,58 @@
+/* tslint:disable prefer-function-over-method */
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataTypeFactory, PayloadDataType } from '../data_type';
+
+export class DynamicBytes extends PayloadDataType {
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+
+    public static matchType(type: string): boolean {
+        return type === 'bytes';
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory, DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!DynamicBytes.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate DynamicBytes with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '${value}'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        const wordsForValue = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedDynamicBytesForValue);
+        const paddedLengthBuf = ethUtil.setLengthLeft(
+            ethUtil.toBuffer(valueBuf.byteLength),
+            Constants.EVM_WORD_WIDTH_IN_BYTES,
+        );
+        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, Constants.HEX_BASE);
+        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const decodedValue = ethUtil.bufferToHex(valueBuf);
+        return decodedValue;
+    }
+
+    public getSignature(): string {
+        return 'bytes';
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/index.ts b/packages/utils/src/abi_encoder/evm_data_types/index.ts
new file mode 100644
index 000000000..fc0edabf1
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/index.ts
@@ -0,0 +1,11 @@
+export * from './address';
+export * from './bool';
+export * from './int';
+export * from './uint';
+export * from './static_bytes';
+export * from './dynamic_bytes';
+export * from './string';
+export * from './pointer';
+export * from './tuple';
+export * from './array';
+export * from './method';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
new file mode 100644
index 000000000..ba5b4cac9
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -0,0 +1,33 @@
+/* tslint:disable prefer-function-over-method */
+import { DataItem } from 'ethereum-types';
+
+import { BigNumber } from '../../configured_bignumber';
+import { DataTypeFactory } from '../data_type';
+
+import { Number } from './number';
+
+export class Int extends Number {
+    private static readonly _matcher = RegExp(
+        '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    public static matchType(type: string): boolean {
+        return Int._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, Int._matcher, dataTypeFactory);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this._width - 1).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(2).toPower(this._width - 1).times(-1);
+    }
+
+    public getSignature(): string {
+        return `int${this._width}`;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
new file mode 100644
index 000000000..e8e717bf1
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -0,0 +1,90 @@
+import { DataItem, MethodAbi } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { DecodingRules, EncodingRules, RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataType, DataTypeFactory, MemberDataType } from '../data_type';
+
+import { StaticBytes } from './static_bytes';
+import { Tuple } from './tuple';
+
+export class Method extends MemberDataType {
+    // TMP
+    public selector: string;
+
+    private readonly _methodSignature: string;
+    private readonly _methodSelector: string;
+    private readonly _returnDataTypes: DataType[];
+    private readonly _returnDataItem: DataItem;
+
+    public constructor(abi: MethodAbi, dataTypeFactory: DataTypeFactory) {
+        super({ type: 'method', name: abi.name, components: abi.inputs }, dataTypeFactory);
+        this._methodSignature = this._computeSignature();
+        this.selector = this._methodSelector = this._computeSelector();
+        this._returnDataTypes = [];
+        this._returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
+        const dummy = new StaticBytes({ type: 'byte', name: 'DUMMY' }, dataTypeFactory); // @TODO TMP
+        _.each(abi.outputs, (dataItem: DataItem) => {
+            this._returnDataTypes.push(this.getFactory().create(dataItem, dummy));
+        });
+    }
+
+    public encode(value: any, rules?: EncodingRules): string {
+        const calldata = super.encode(value, rules, this.selector);
+        return calldata;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules): any[] | object {
+        if (!calldata.startsWith(this.selector)) {
+            throw new Error(
+                `Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`,
+            );
+        }
+        const hasSelector = true;
+        const value = super.decode(calldata, rules, hasSelector);
+        return value;
+    }
+
+    public encodeReturnValues(value: any, rules?: EncodingRules): string {
+        const returnDataType = new Tuple(this._returnDataItem, this.getFactory());
+        const returndata = returnDataType.encode(value, rules);
+        return returndata;
+    }
+
+    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
+        const returnValues: any[] = [];
+        const rules_: DecodingRules = rules ? rules : { structsAsObjects: false };
+        const rawReturnData = new RawCalldata(returndata, false);
+        _.each(this._returnDataTypes, (dataType: DataType) => {
+            returnValues.push(dataType.generateValue(rawReturnData, rules_));
+        });
+        return returnValues;
+    }
+
+    public getSignature(): string {
+        return this._methodSignature;
+    }
+
+    public getSelector(): string {
+        return this._methodSelector;
+    }
+
+    private _computeSignature(): string {
+        const memberSignature = this._computeSignatureOfMembers();
+        const methodSignature = `${this.getDataItem().name}${memberSignature}`;
+        return methodSignature;
+    }
+
+    private _computeSelector(): string {
+        const signature = this._computeSignature();
+        const selector = ethUtil.bufferToHex(
+            ethUtil.toBuffer(
+                ethUtil
+                    .sha3(signature)
+                    .slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES),
+            ),
+        );
+        return selector;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/number.ts b/packages/utils/src/abi_encoder/evm_data_types/number.ts
new file mode 100644
index 000000000..17201362e
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/number.ts
@@ -0,0 +1,100 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../../configured_bignumber';
+import { RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataTypeFactory, PayloadDataType } from '../data_type';
+
+export abstract class Number extends PayloadDataType {
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _MAX_WIDTH: number = 256;
+    private static readonly _DEFAULT_WIDTH: number = Number._MAX_WIDTH;
+    protected _width: number;
+
+    constructor(dataItem: DataItem, matcher: RegExp, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory, Number._SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = matcher.exec(dataItem.type);
+        if (matches === null) {
+            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
+        }
+        this._width =
+            matches !== null && matches.length === 2 && matches[1] !== undefined
+                ? parseInt(matches[1], Constants.DEC_BASE)
+                : (this._width = Number._DEFAULT_WIDTH);
+    }
+
+    public encodeValue(value_: BigNumber | string | number): Buffer {
+        const value = new BigNumber(value_, 10);
+        if (value.greaterThan(this.getMaxValue())) {
+            throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`);
+        } else if (value.lessThan(this.getMinValue())) {
+            throw new Error(`Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`);
+        }
+
+        let valueBuf: Buffer;
+        if (value.greaterThanOrEqualTo(0)) {
+            valueBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${value.toString(Constants.HEX_BASE)}`),
+                Constants.EVM_WORD_WIDTH_IN_BYTES,
+            );
+        } else {
+            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
+            // Step 1/3: Convert value to positive binary string
+            const binBase = 2;
+            const valueBin = value.times(-1).toString(binBase);
+
+            // Step 2/3: Invert binary value
+            let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
+            _.each(valueBin, (bit: string) => {
+                invertedValueBin += bit === '1' ? '0' : '1';
+            });
+            const invertedValue = new BigNumber(invertedValueBin, binBase);
+
+            // Step 3/3: Add 1 to inverted value
+            // The result is the two's-complement represent of the input value.
+            const negativeValue = invertedValue.plus(1);
+
+            // Convert the negated value to a hex string
+            valueBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${negativeValue.toString(Constants.HEX_BASE)}`),
+                Constants.EVM_WORD_WIDTH_IN_BYTES,
+            );
+        }
+
+        return valueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): BigNumber {
+        const paddedValueBuf = calldata.popWord();
+        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
+        let value = new BigNumber(paddedValueHex, 16);
+        if (this.getMinValue().lessThan(0)) {
+            // Check if we're negative
+            const valueBin = value.toString(Constants.BIN_BASE);
+            if (valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1')) {
+                // Negative
+                // Step 1/3: Invert binary value
+                let invertedValueBin = '';
+                _.each(valueBin, (bit: string) => {
+                    invertedValueBin += bit === '1' ? '0' : '1';
+                });
+                const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
+
+                // Step 2/3: Add 1 to inverted value
+                // The result is the two's-complement represent of the input value.
+                const positiveValue = invertedValue.plus(1);
+
+                // Step 3/3: Invert positive value
+                const negativeValue = positiveValue.times(-1);
+                value = negativeValue;
+            }
+        }
+
+        return value;
+    }
+
+    public abstract getMaxValue(): BigNumber;
+    public abstract getMinValue(): BigNumber;
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
new file mode 100644
index 000000000..e0bd3509c
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -0,0 +1,15 @@
+import { DataItem } from 'ethereum-types';
+
+import { DataType, DataTypeFactory, DependentDataType } from '../data_type';
+
+export class Pointer extends DependentDataType {
+    constructor(destDataType: DataType, parentDataType: DataType, dataTypeFactory: DataTypeFactory) {
+        const destDataItem = destDataType.getDataItem();
+        const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` };
+        super(dataItem, dataTypeFactory, destDataType, parentDataType);
+    }
+
+    public getSignature(): string {
+        return this._dependency.getSignature();
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
new file mode 100644
index 000000000..309dca234
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -0,0 +1,68 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataTypeFactory, PayloadDataType } from '../data_type';
+
+export class StaticBytes extends PayloadDataType {
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _matcher = RegExp(
+        '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
+    );
+
+    private static readonly _DEFAULT_WIDTH = 1;
+    private readonly _width: number;
+
+    public static matchType(type: string): boolean {
+        return StaticBytes._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory, StaticBytes._SIZE_KNOWN_AT_COMPILE_TIME);
+        const matches = StaticBytes._matcher.exec(dataItem.type);
+        if (!StaticBytes.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
+        }
+        this._width =
+            matches !== null && matches.length === 3 && matches[2] !== undefined
+                ? parseInt(matches[2], Constants.DEC_BASE)
+                : StaticBytes._DEFAULT_WIDTH;
+    }
+
+    public getSignature(): string {
+        // Note that `byte` reduces to `bytes1`
+        return `bytes${this._width}`;
+    }
+
+    public encodeValue(value: string | Buffer): Buffer {
+        // Sanity check if string
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
+        }
+        // Convert value into a buffer and do bounds checking
+        const valueBuf = ethUtil.toBuffer(value);
+        if (valueBuf.byteLength > this._width) {
+            throw new Error(
+                `Tried to assign ${value} (${
+                    valueBuf.byteLength
+                } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
+            );
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+
+        // Store value as hex
+        const evmWordWidth = 32;
+        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
+        return paddedValue;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const paddedValueBuf = calldata.popWord();
+        const valueBuf = paddedValueBuf.slice(0, this._width);
+        const value = ethUtil.bufferToHex(valueBuf);
+        return value;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
new file mode 100644
index 000000000..96b36e735
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -0,0 +1,47 @@
+/* tslint:disable prefer-function-over-method */
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DataTypeFactory, PayloadDataType } from '../data_type';
+
+export class String extends PayloadDataType {
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+
+    public static matchType(type: string): boolean {
+        return type === 'string';
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory, String._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!String.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
+        }
+    }
+
+    public encodeValue(value: string): Buffer {
+        const wordsForValue = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedDynamicBytesForValue);
+        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+        return encodedValueBuf;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const lengthBuf = calldata.popWord();
+        const lengthHex = ethUtil.bufferToHex(lengthBuf);
+        const length = parseInt(lengthHex, Constants.HEX_BASE);
+        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const paddedValueBuf = calldata.popWords(wordsForValue);
+        const valueBuf = paddedValueBuf.slice(0, length);
+        const value = valueBuf.toString('ascii');
+        return value;
+    }
+
+    public getSignature(): string {
+        return 'string';
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
new file mode 100644
index 000000000..0db29c1eb
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -0,0 +1,23 @@
+import { DataItem } from 'ethereum-types';
+
+import { DataTypeFactory, MemberDataType } from '../data_type';
+
+export class Tuple extends MemberDataType {
+    private readonly _tupleSignature: string;
+
+    public static matchType(type: string): boolean {
+        return type === 'tuple';
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, dataTypeFactory);
+        if (!Tuple.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
+        }
+        this._tupleSignature = this._computeSignatureOfMembers();
+    }
+
+    public getSignature(): string {
+        return this._tupleSignature;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
new file mode 100644
index 000000000..86b31ab4c
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -0,0 +1,33 @@
+/* tslint:disable prefer-function-over-method */
+import { DataItem } from 'ethereum-types';
+
+import { BigNumber } from '../../configured_bignumber';
+import { DataTypeFactory } from '../data_type';
+
+import { Number } from './number';
+
+export class UInt extends Number {
+    private static readonly _matcher = RegExp(
+        '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
+    );
+
+    public static matchType(type: string): boolean {
+        return UInt._matcher.test(type);
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        super(dataItem, UInt._matcher, dataTypeFactory);
+    }
+
+    public getMaxValue(): BigNumber {
+        return new BigNumber(2).toPower(this._width).sub(1);
+    }
+
+    public getMinValue(): BigNumber {
+        return new BigNumber(0);
+    }
+
+    public getSignature(): string {
+        return `uint${this._width}`;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts
index 95ad84ac9..a62569fab 100644
--- a/packages/utils/src/abi_encoder/index.ts
+++ b/packages/utils/src/abi_encoder/index.ts
@@ -1,2 +1,2 @@
 export { EncodingRules, DecodingRules } from './calldata';
-export * from './evm_data_types';
+export * from './evm_data_type_factory';
-- 
cgit v1.2.3


From aed8b083b587e7b420ac6129b04004dea95c3f3a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 13:24:45 -0800
Subject: Split Calldata into multiple files - 1 class per file

---
 packages/utils/src/abi_encoder/calldata.ts         | 531 ---------------------
 .../utils/src/abi_encoder/calldata/calldata.ts     | 224 +++++++++
 .../src/abi_encoder/calldata/calldata_block.ts     |  77 +++
 .../src/abi_encoder/calldata/calldata_blocks.ts    |   3 +
 .../calldata/dependent_calldata_block.ts           |  59 +++
 packages/utils/src/abi_encoder/calldata/index.ts   |   6 +
 .../abi_encoder/calldata/member_calldata_block.ts  |  48 ++
 .../abi_encoder/calldata/payload_calldata_block.ts |  20 +
 .../utils/src/abi_encoder/calldata/raw_calldata.ts |  82 ++++
 packages/utils/src/abi_encoder/data_type.ts        |   4 +-
 .../utils/src/abi_encoder/evm_data_types/method.ts |   3 +-
 packages/utils/src/abi_encoder/index.ts            |   2 +-
 packages/utils/src/abi_encoder/utils/queue.ts      |  39 ++
 packages/utils/src/abi_encoder/utils/rules.ts      |   8 +
 14 files changed, 571 insertions(+), 535 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/calldata.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/calldata.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/calldata_block.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/index.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/raw_calldata.ts
 create mode 100644 packages/utils/src/abi_encoder/utils/queue.ts
 create mode 100644 packages/utils/src/abi_encoder/utils/rules.ts

diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
deleted file mode 100644
index d108ef0a7..000000000
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ /dev/null
@@ -1,531 +0,0 @@
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-import * as Constants from './constants';
-
-export interface DecodingRules {
-    structsAsObjects: boolean;
-}
-
-export interface EncodingRules {
-    optimize?: boolean;
-    annotate?: boolean;
-}
-
-export abstract class CalldataBlock {
-    private readonly _signature: string;
-    private readonly _parentName: string;
-    private _name: string;
-    private _offsetInBytes: number;
-    private _headerSizeInBytes: number;
-    private _bodySizeInBytes: number;
-
-    constructor(
-        name: string,
-        signature: string,
-        parentName: string,
-        headerSizeInBytes: number,
-        bodySizeInBytes: number,
-    ) {
-        this._name = name;
-        this._signature = signature;
-        this._parentName = parentName;
-        this._offsetInBytes = 0;
-        this._headerSizeInBytes = headerSizeInBytes;
-        this._bodySizeInBytes = bodySizeInBytes;
-    }
-
-    protected _setHeaderSize(headerSizeInBytes: number): void {
-        this._headerSizeInBytes = headerSizeInBytes;
-    }
-
-    protected _setBodySize(bodySizeInBytes: number): void {
-        this._bodySizeInBytes = bodySizeInBytes;
-    }
-
-    protected _setName(name: string): void {
-        this._name = name;
-    }
-
-    public getName(): string {
-        return this._name;
-    }
-
-    public getParentName(): string {
-        return this._parentName;
-    }
-
-    public getSignature(): string {
-        return this._signature;
-    }
-    public getHeaderSizeInBytes(): number {
-        return this._headerSizeInBytes;
-    }
-
-    public getBodySizeInBytes(): number {
-        return this._bodySizeInBytes;
-    }
-
-    public getSizeInBytes(): number {
-        return this.getHeaderSizeInBytes() + this.getBodySizeInBytes();
-    }
-
-    public getOffsetInBytes(): number {
-        return this._offsetInBytes;
-    }
-
-    public setOffset(offsetInBytes: number): void {
-        this._offsetInBytes = offsetInBytes;
-    }
-
-    public computeHash(): Buffer {
-        const rawData = this.getRawData();
-        const hash = ethUtil.sha3(rawData);
-        return hash;
-    }
-
-    public abstract toBuffer(): Buffer;
-    public abstract getRawData(): Buffer;
-}
-
-export class PayloadCalldataBlock extends CalldataBlock {
-    private readonly _payload: Buffer;
-
-    constructor(name: string, signature: string, parentName: string, payload: Buffer) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = payload.byteLength;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
-        this._payload = payload;
-    }
-
-    public toBuffer(): Buffer {
-        return this._payload;
-    }
-
-    public getRawData(): Buffer {
-        return this._payload;
-    }
-}
-
-export class DependentCalldataBlock extends CalldataBlock {
-    public static readonly RAW_DATA_START = new Buffer('<');
-    public static readonly RAW_DATA_END = new Buffer('>');
-    private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    private static readonly _EMPTY_HEADER_SIZE = 0;
-    private readonly _parent: CalldataBlock;
-    private readonly _dependency: CalldataBlock;
-    private _aliasFor: CalldataBlock | undefined;
-
-    constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) {
-        const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE;
-        const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
-        this._parent = parent;
-        this._dependency = dependency;
-        this._aliasFor = undefined;
-    }
-
-    public toBuffer(): Buffer {
-        const destinationOffset =
-            this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
-        const parentOffset = this._parent.getOffsetInBytes();
-        const parentHeaderSize = this._parent.getHeaderSizeInBytes();
-        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
-        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`);
-        const evmWordWidthInBytes = 32;
-        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
-        return pointerBufPadded;
-    }
-
-    public getDependency(): CalldataBlock {
-        return this._dependency;
-    }
-
-    public setAlias(block: CalldataBlock): void {
-        this._aliasFor = block;
-        this._setName(`${this.getName()} (alias for ${block.getName()})`);
-    }
-
-    public getAlias(): CalldataBlock | undefined {
-        return this._aliasFor;
-    }
-
-    public getRawData(): Buffer {
-        const dependencyRawData = this._dependency.getRawData();
-        const rawDataComponents: Buffer[] = [];
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
-        rawDataComponents.push(dependencyRawData);
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-}
-
-export class MemberCalldataBlock extends CalldataBlock {
-    private _header: Buffer | undefined;
-    private _members: CalldataBlock[];
-
-    constructor(name: string, signature: string, parentName: string) {
-        super(name, signature, parentName, 0, 0);
-        this._members = [];
-        this._header = undefined;
-    }
-
-    public getRawData(): Buffer {
-        const rawDataComponents: Buffer[] = [];
-        if (this._header !== undefined) {
-            rawDataComponents.push(this._header);
-        }
-        _.each(this._members, (member: CalldataBlock) => {
-            const memberBuffer = member.getRawData();
-            rawDataComponents.push(memberBuffer);
-        });
-
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-
-    public setMembers(members: CalldataBlock[]): void {
-        this._members = members;
-    }
-
-    public setHeader(header: Buffer): void {
-        this._setHeaderSize(header.byteLength);
-        this._header = header;
-    }
-
-    public toBuffer(): Buffer {
-        if (this._header !== undefined) {
-            return this._header;
-        }
-        return new Buffer('');
-    }
-
-    public getMembers(): CalldataBlock[] {
-        return this._members;
-    }
-}
-
-class Queue<T> {
-    private _store: T[] = [];
-    public push(val: T): void {
-        this._store.push(val);
-    }
-    public pushFront(val: T): void {
-        this._store.unshift(val);
-    }
-    public pop(): T | undefined {
-        return this._store.shift();
-    }
-    public popBack(): T | undefined {
-        if (this._store.length === 0) {
-            return undefined;
-        }
-        const backElement = this._store.splice(-1, 1)[0];
-        return backElement;
-    }
-    public merge(q: Queue<T>): void {
-        this._store = this._store.concat(q._store);
-    }
-    public mergeFront(q: Queue<T>): void {
-        this._store = q._store.concat(this._store);
-    }
-    public getStore(): T[] {
-        return this._store;
-    }
-    public peek(): T | undefined {
-        return this._store.length >= 0 ? this._store[0] : undefined;
-    }
-}
-
-export class Calldata {
-    private readonly _rules: EncodingRules;
-    private _selector: string;
-    private _sizeInBytes: number;
-    private _root: CalldataBlock | undefined;
-
-    private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
-        const blockQueue = new Queue<CalldataBlock>();
-
-        // Base Case
-        if (!(block instanceof MemberCalldataBlock)) {
-            blockQueue.push(block);
-            return blockQueue;
-        }
-
-        // This is a Member Block
-        const memberBlock = block;
-        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof MemberCalldataBlock) {
-                blockQueue.mergeFront(Calldata._createQueue(member));
-            } else {
-                blockQueue.pushFront(member);
-            }
-        });
-
-        // Children
-        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof DependentCalldataBlock && member.getAlias() === undefined) {
-                const dependency = member.getDependency();
-                if (dependency instanceof MemberCalldataBlock) {
-                    blockQueue.merge(Calldata._createQueue(dependency));
-                } else {
-                    blockQueue.push(dependency);
-                }
-            }
-        });
-
-        blockQueue.pushFront(memberBlock);
-        return blockQueue;
-    }
-
-    public constructor(rules: EncodingRules) {
-        this._rules = rules;
-        this._selector = '';
-        this._sizeInBytes = 0;
-        this._root = undefined;
-    }
-
-    public optimize(): void {
-        if (this._root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const blocksByHash: { [key: string]: CalldataBlock } = {};
-
-        // 1. Create a queue of subtrees by hash
-        // Note that they are ordered the same as
-        const subtreeQueue = Calldata._createQueue(this._root);
-        let block: CalldataBlock | undefined;
-        for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) {
-            if (block instanceof DependentCalldataBlock) {
-                const dependencyBlockHashBuf = block.getDependency().computeHash();
-                const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
-                if (dependencyBlockHash in blocksByHash) {
-                    const blockWithSameHash = blocksByHash[dependencyBlockHash];
-                    if (blockWithSameHash !== block.getDependency()) {
-                        block.setAlias(blockWithSameHash);
-                    }
-                }
-                continue;
-            }
-
-            const blockHashBuf = block.computeHash();
-            const blockHash = ethUtil.bufferToHex(blockHashBuf);
-            if (!(blockHash in blocksByHash)) {
-                blocksByHash[blockHash] = block;
-            }
-        }
-    }
-
-    public toHexString(): string {
-        if (this._root === undefined) {
-            throw new Error('expected root');
-        }
-
-        if (this._rules.optimize) {
-            this.optimize();
-        }
-
-        const offsetQueue = Calldata._createQueue(this._root);
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        for (block = offsetQueue.pop(); block !== undefined; block = offsetQueue.pop()) {
-            block.setOffset(offset);
-            offset += block.getSizeInBytes();
-        }
-
-        const hexValue = this._rules.annotate ? this._generateAnnotatedHexString() : this._generateCondensedHexString();
-        return hexValue;
-    }
-
-    public getSelectorHex(): string {
-        return this._selector;
-    }
-
-    public getSizeInBytes(): number {
-        return this._sizeInBytes;
-    }
-
-    public setRoot(block: CalldataBlock): void {
-        this._root = block;
-        this._sizeInBytes += block.getSizeInBytes();
-    }
-
-    public setSelector(selector: string): void {
-        this._selector = selector.startsWith('0x') ? selector : `$0x${selector}`;
-        if (this._selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
-            throw new Error(`Invalid selector '${this._selector}'`);
-        }
-        this._sizeInBytes += Constants.HEX_SELECTOR_LENGTH_IN_BYTES; // @TODO: Used to be += 8. Bad?
-    }
-
-    private _generateAnnotatedHexString(): string {
-        let hexValue = `${this._selector}`;
-        if (this._root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = Calldata._createQueue(this._root);
-
-        let block: CalldataBlock | undefined;
-        let offset = 0;
-        const functionBlock = valueQueue.peek();
-        const functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
-        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
-            // Process each block 1 word at a time
-            const size = block.getSizeInBytes();
-            const name = block.getName();
-            const parentName = block.getParentName();
-            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');
-
-            // Current offset
-            let offsetStr = '';
-
-            // If this block is empty then it's a newline
-            const offsetPadding = 10;
-            const valuePadding = 74;
-            const namePadding = 80;
-            const evmWordStartIndex = 0;
-            const emptySize = 0;
-            let value = '';
-            let nameStr = '';
-            let line = '';
-            if (size === emptySize) {
-                offsetStr = ' '.repeat(offsetPadding);
-                value = ' '.repeat(valuePadding);
-                nameStr = `### ${prettyName.padEnd(namePadding)}`;
-                line = `\n${offsetStr}${value}${nameStr}`;
-            } else {
-                offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
-                value = ethUtil
-                    .stripHexPrefix(
-                        ethUtil.bufferToHex(
-                            block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES),
-                        ),
-                    )
-                    .padEnd(valuePadding);
-                if (block instanceof MemberCalldataBlock) {
-                    nameStr = `### ${prettyName.padEnd(namePadding)}`;
-                    line = `\n${offsetStr}${value}${nameStr}`;
-                } else {
-                    nameStr = `    ${prettyName.padEnd(namePadding)}`;
-                    line = `${offsetStr}${value}${nameStr}`;
-                }
-            }
-
-            for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) {
-                offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
-                value = ethUtil
-                    .stripHexPrefix(
-                        ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)),
-                    )
-                    .padEnd(valuePadding);
-                nameStr = ' '.repeat(namePadding);
-                line = `${line}\n${offsetStr}${value}${nameStr}`;
-            }
-
-            // Append to hex value
-            hexValue = `${hexValue}\n${line}`;
-            offset += size;
-        }
-
-        return hexValue;
-    }
-
-    private _generateCondensedHexString(): string {
-        const selectorBuffer = ethUtil.toBuffer(this._selector);
-        if (this._root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const valueQueue = Calldata._createQueue(this._root);
-        const valueBufs: Buffer[] = [selectorBuffer];
-        let block: CalldataBlock | undefined;
-        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
-            valueBufs.push(block.toBuffer());
-        }
-
-        const combinedBuffers = Buffer.concat(valueBufs);
-        const hexValue = ethUtil.bufferToHex(combinedBuffers);
-        return hexValue;
-    }
-}
-
-export class RawCalldata {
-    private static readonly _INITIAL_OFFSET = 0;
-    private readonly _value: Buffer;
-    private readonly _selector: string;
-    private readonly _scopes: Queue<number>;
-    private _offset: number; // tracks current offset into raw calldata; used for parsing
-
-    constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Expected raw calldata to start with '0x'`);
-        }
-        const valueBuf = ethUtil.toBuffer(value);
-        if (hasSelectorPrefix) {
-            this._selector = ethUtil.bufferToHex(
-                valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES),
-            );
-            this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector
-        } else {
-            this._selector = '0x';
-            this._value = valueBuf;
-        }
-
-        this._scopes = new Queue<number>();
-        this._scopes.push(RawCalldata._INITIAL_OFFSET);
-        this._offset = RawCalldata._INITIAL_OFFSET;
-    }
-
-    public popBytes(lengthInBytes: number): Buffer {
-        const value = this._value.slice(this._offset, this._offset + lengthInBytes);
-        this.setOffset(this._offset + lengthInBytes);
-        return value;
-    }
-
-    public popWord(): Buffer {
-        const wordInBytes = 32;
-        return this.popBytes(wordInBytes);
-    }
-
-    public popWords(length: number): Buffer {
-        const wordInBytes = 32;
-        return this.popBytes(length * wordInBytes);
-    }
-
-    public readBytes(from: number, to: number): Buffer {
-        const value = this._value.slice(from, to);
-        return value;
-    }
-
-    public setOffset(offsetInBytes: number): void {
-        this._offset = offsetInBytes;
-    }
-
-    public startScope(): void {
-        this._scopes.pushFront(this._offset);
-    }
-
-    public endScope(): void {
-        this._scopes.pop();
-    }
-
-    public getOffset(): number {
-        return this._offset;
-    }
-
-    public toAbsoluteOffset(relativeOffset: number): number {
-        const scopeOffset = this._scopes.peek();
-        if (scopeOffset === undefined) {
-            throw new Error(`Tried to access undefined scope.`);
-        }
-        const absoluteOffset = relativeOffset + scopeOffset;
-        return absoluteOffset;
-    }
-
-    public getSelector(): string {
-        return this._selector;
-    }
-}
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
new file mode 100644
index 000000000..5ac4c1fe7
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -0,0 +1,224 @@
+
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import * as Constants from '../constants';
+import { Queue } from '../utils/queue';
+import { EncodingRules } from '../utils/rules';
+
+import { CalldataBlock } from './calldata_block';
+import * as CalldataBlocks from './calldata_blocks';
+
+export class Calldata {
+    private readonly _rules: EncodingRules;
+    private _selector: string;
+    private _sizeInBytes: number;
+    private _root: CalldataBlock | undefined;
+
+    private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
+        const blockQueue = new Queue<CalldataBlock>();
+
+        // Base Case
+        if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) {
+            blockQueue.push(block);
+            return blockQueue;
+        }
+
+        // This is a Member Block
+        const memberBlock = block;
+        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof CalldataBlocks.MemberCalldataBlock) {
+                blockQueue.mergeFront(Calldata._createQueue(member));
+            } else {
+                blockQueue.pushFront(member);
+            }
+        });
+
+        // Children
+        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
+            if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) {
+                const dependency = member.getDependency();
+                if (dependency instanceof CalldataBlocks.MemberCalldataBlock) {
+                    blockQueue.merge(Calldata._createQueue(dependency));
+                } else {
+                    blockQueue.push(dependency);
+                }
+            }
+        });
+
+        blockQueue.pushFront(memberBlock);
+        return blockQueue;
+    }
+
+    public constructor(rules: EncodingRules) {
+        this._rules = rules;
+        this._selector = '';
+        this._sizeInBytes = 0;
+        this._root = undefined;
+    }
+
+    public optimize(): void {
+        if (this._root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const blocksByHash: { [key: string]: CalldataBlock } = {};
+
+        // 1. Create a queue of subtrees by hash
+        // Note that they are ordered the same as
+        const subtreeQueue = Calldata._createQueue(this._root);
+        let block: CalldataBlock | undefined;
+        for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) {
+            if (block instanceof CalldataBlocks.DependentCalldataBlock) {
+                const dependencyBlockHashBuf = block.getDependency().computeHash();
+                const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
+                if (dependencyBlockHash in blocksByHash) {
+                    const blockWithSameHash = blocksByHash[dependencyBlockHash];
+                    if (blockWithSameHash !== block.getDependency()) {
+                        block.setAlias(blockWithSameHash);
+                    }
+                }
+                continue;
+            }
+
+            const blockHashBuf = block.computeHash();
+            const blockHash = ethUtil.bufferToHex(blockHashBuf);
+            if (!(blockHash in blocksByHash)) {
+                blocksByHash[blockHash] = block;
+            }
+        }
+    }
+
+    public toHexString(): string {
+        if (this._root === undefined) {
+            throw new Error('expected root');
+        }
+
+        if (this._rules.optimize) {
+            this.optimize();
+        }
+
+        const offsetQueue = Calldata._createQueue(this._root);
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        for (block = offsetQueue.pop(); block !== undefined; block = offsetQueue.pop()) {
+            block.setOffset(offset);
+            offset += block.getSizeInBytes();
+        }
+
+        const hexValue = this._rules.annotate ? this._generateAnnotatedHexString() : this._generateCondensedHexString();
+        return hexValue;
+    }
+
+    public getSelectorHex(): string {
+        return this._selector;
+    }
+
+    public getSizeInBytes(): number {
+        return this._sizeInBytes;
+    }
+
+    public setRoot(block: CalldataBlock): void {
+        this._root = block;
+        this._sizeInBytes += block.getSizeInBytes();
+    }
+
+    public setSelector(selector: string): void {
+        this._selector = selector.startsWith('0x') ? selector : `$0x${selector}`;
+        if (this._selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
+            throw new Error(`Invalid selector '${this._selector}'`);
+        }
+        this._sizeInBytes += Constants.HEX_SELECTOR_LENGTH_IN_BYTES; // @TODO: Used to be += 8. Bad?
+    }
+
+    private _generateAnnotatedHexString(): string {
+        let hexValue = `${this._selector}`;
+        if (this._root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = Calldata._createQueue(this._root);
+
+        let block: CalldataBlock | undefined;
+        let offset = 0;
+        const functionBlock = valueQueue.peek();
+        const functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
+        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
+            // Process each block 1 word at a time
+            const size = block.getSizeInBytes();
+            const name = block.getName();
+            const parentName = block.getParentName();
+            const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');
+
+            // Current offset
+            let offsetStr = '';
+
+            // If this block is empty then it's a newline
+            const offsetPadding = 10;
+            const valuePadding = 74;
+            const namePadding = 80;
+            const evmWordStartIndex = 0;
+            const emptySize = 0;
+            let value = '';
+            let nameStr = '';
+            let line = '';
+            if (size === emptySize) {
+                offsetStr = ' '.repeat(offsetPadding);
+                value = ' '.repeat(valuePadding);
+                nameStr = `### ${prettyName.padEnd(namePadding)}`;
+                line = `\n${offsetStr}${value}${nameStr}`;
+            } else {
+                offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
+                value = ethUtil
+                    .stripHexPrefix(
+                        ethUtil.bufferToHex(
+                            block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES),
+                        ),
+                    )
+                    .padEnd(valuePadding);
+                if (block instanceof CalldataBlocks.MemberCalldataBlock) {
+                    nameStr = `### ${prettyName.padEnd(namePadding)}`;
+                    line = `\n${offsetStr}${value}${nameStr}`;
+                } else {
+                    nameStr = `    ${prettyName.padEnd(namePadding)}`;
+                    line = `${offsetStr}${value}${nameStr}`;
+                }
+            }
+
+            for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) {
+                offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
+                value = ethUtil
+                    .stripHexPrefix(
+                        ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)),
+                    )
+                    .padEnd(valuePadding);
+                nameStr = ' '.repeat(namePadding);
+                line = `${line}\n${offsetStr}${value}${nameStr}`;
+            }
+
+            // Append to hex value
+            hexValue = `${hexValue}\n${line}`;
+            offset += size;
+        }
+
+        return hexValue;
+    }
+
+    private _generateCondensedHexString(): string {
+        const selectorBuffer = ethUtil.toBuffer(this._selector);
+        if (this._root === undefined) {
+            throw new Error('expected root');
+        }
+
+        const valueQueue = Calldata._createQueue(this._root);
+        const valueBufs: Buffer[] = [selectorBuffer];
+        let block: CalldataBlock | undefined;
+        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
+            valueBufs.push(block.toBuffer());
+        }
+
+        const combinedBuffers = Buffer.concat(valueBufs);
+        const hexValue = ethUtil.bufferToHex(combinedBuffers);
+        return hexValue;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/calldata/calldata_block.ts b/packages/utils/src/abi_encoder/calldata/calldata_block.ts
new file mode 100644
index 000000000..35bd994e5
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/calldata_block.ts
@@ -0,0 +1,77 @@
+import * as ethUtil from 'ethereumjs-util';
+
+export abstract class CalldataBlock {
+    private readonly _signature: string;
+    private readonly _parentName: string;
+    private _name: string;
+    private _offsetInBytes: number;
+    private _headerSizeInBytes: number;
+    private _bodySizeInBytes: number;
+
+    constructor(
+        name: string,
+        signature: string,
+        parentName: string,
+        headerSizeInBytes: number,
+        bodySizeInBytes: number,
+    ) {
+        this._name = name;
+        this._signature = signature;
+        this._parentName = parentName;
+        this._offsetInBytes = 0;
+        this._headerSizeInBytes = headerSizeInBytes;
+        this._bodySizeInBytes = bodySizeInBytes;
+    }
+
+    protected _setHeaderSize(headerSizeInBytes: number): void {
+        this._headerSizeInBytes = headerSizeInBytes;
+    }
+
+    protected _setBodySize(bodySizeInBytes: number): void {
+        this._bodySizeInBytes = bodySizeInBytes;
+    }
+
+    protected _setName(name: string): void {
+        this._name = name;
+    }
+
+    public getName(): string {
+        return this._name;
+    }
+
+    public getParentName(): string {
+        return this._parentName;
+    }
+
+    public getSignature(): string {
+        return this._signature;
+    }
+    public getHeaderSizeInBytes(): number {
+        return this._headerSizeInBytes;
+    }
+
+    public getBodySizeInBytes(): number {
+        return this._bodySizeInBytes;
+    }
+
+    public getSizeInBytes(): number {
+        return this.getHeaderSizeInBytes() + this.getBodySizeInBytes();
+    }
+
+    public getOffsetInBytes(): number {
+        return this._offsetInBytes;
+    }
+
+    public setOffset(offsetInBytes: number): void {
+        this._offsetInBytes = offsetInBytes;
+    }
+
+    public computeHash(): Buffer {
+        const rawData = this.getRawData();
+        const hash = ethUtil.sha3(rawData);
+        return hash;
+    }
+
+    public abstract toBuffer(): Buffer;
+    public abstract getRawData(): Buffer;
+}
diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
new file mode 100644
index 000000000..37660ef21
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
@@ -0,0 +1,3 @@
+export * from './dependent_calldata_block';
+export * from './member_calldata_block';
+export * from './payload_calldata_block';
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
new file mode 100644
index 000000000..d6870ec0b
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
@@ -0,0 +1,59 @@
+import * as ethUtil from 'ethereumjs-util';
+
+import * as Constants from '../constants';
+
+import { CalldataBlock } from './calldata_block';
+
+export class DependentCalldataBlock extends CalldataBlock {
+    public static readonly RAW_DATA_START = new Buffer('<');
+    public static readonly RAW_DATA_END = new Buffer('>');
+    private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private static readonly _EMPTY_HEADER_SIZE = 0;
+    private readonly _parent: CalldataBlock;
+    private readonly _dependency: CalldataBlock;
+    private _aliasFor: CalldataBlock | undefined;
+
+    constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) {
+        const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE;
+        const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
+        this._parent = parent;
+        this._dependency = dependency;
+        this._aliasFor = undefined;
+    }
+
+    public toBuffer(): Buffer {
+        const destinationOffset =
+            this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
+        const parentOffset = this._parent.getOffsetInBytes();
+        const parentHeaderSize = this._parent.getHeaderSizeInBytes();
+        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
+        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`);
+        const evmWordWidthInBytes = 32;
+        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
+        return pointerBufPadded;
+    }
+
+    public getDependency(): CalldataBlock {
+        return this._dependency;
+    }
+
+    public setAlias(block: CalldataBlock): void {
+        this._aliasFor = block;
+        this._setName(`${this.getName()} (alias for ${block.getName()})`);
+    }
+
+    public getAlias(): CalldataBlock | undefined {
+        return this._aliasFor;
+    }
+
+    public getRawData(): Buffer {
+        const dependencyRawData = this._dependency.getRawData();
+        const rawDataComponents: Buffer[] = [];
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
+        rawDataComponents.push(dependencyRawData);
+        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts
new file mode 100644
index 000000000..0e1f57a2d
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/index.ts
@@ -0,0 +1,6 @@
+export * from './calldata_block';
+export * from './dependent_calldata_block';
+export * from './payload_calldata_block';
+export * from './member_calldata_block';
+export * from './calldata';
+export * from './raw_calldata';
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
new file mode 100644
index 000000000..e9bcb2f34
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
@@ -0,0 +1,48 @@
+import * as _ from 'lodash';
+
+import { CalldataBlock } from './calldata_block';
+
+export class MemberCalldataBlock extends CalldataBlock {
+    private _header: Buffer | undefined;
+    private _members: CalldataBlock[];
+
+    constructor(name: string, signature: string, parentName: string) {
+        super(name, signature, parentName, 0, 0);
+        this._members = [];
+        this._header = undefined;
+    }
+
+    public getRawData(): Buffer {
+        const rawDataComponents: Buffer[] = [];
+        if (this._header !== undefined) {
+            rawDataComponents.push(this._header);
+        }
+        _.each(this._members, (member: CalldataBlock) => {
+            const memberBuffer = member.getRawData();
+            rawDataComponents.push(memberBuffer);
+        });
+
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+
+    public setMembers(members: CalldataBlock[]): void {
+        this._members = members;
+    }
+
+    public setHeader(header: Buffer): void {
+        this._setHeaderSize(header.byteLength);
+        this._header = header;
+    }
+
+    public toBuffer(): Buffer {
+        if (this._header !== undefined) {
+            return this._header;
+        }
+        return new Buffer('');
+    }
+
+    public getMembers(): CalldataBlock[] {
+        return this._members;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
new file mode 100644
index 000000000..81a88bc19
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
@@ -0,0 +1,20 @@
+import { CalldataBlock } from './calldata_block';
+
+export class PayloadCalldataBlock extends CalldataBlock {
+    private readonly _payload: Buffer;
+
+    constructor(name: string, signature: string, parentName: string, payload: Buffer) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = payload.byteLength;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
+        this._payload = payload;
+    }
+
+    public toBuffer(): Buffer {
+        return this._payload;
+    }
+
+    public getRawData(): Buffer {
+        return this._payload;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
new file mode 100644
index 000000000..8b946ee4b
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -0,0 +1,82 @@
+import * as ethUtil from 'ethereumjs-util';
+
+import * as Constants from '../constants';
+import { Queue } from '../utils/queue';
+
+export class RawCalldata {
+    private static readonly _INITIAL_OFFSET = 0;
+    private readonly _value: Buffer;
+    private readonly _selector: string;
+    private readonly _scopes: Queue<number>;
+    private _offset: number; // tracks current offset into raw calldata; used for parsing
+
+    constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) {
+        if (typeof value === 'string' && !value.startsWith('0x')) {
+            throw new Error(`Expected raw calldata to start with '0x'`);
+        }
+        const valueBuf = ethUtil.toBuffer(value);
+        if (hasSelectorPrefix) {
+            this._selector = ethUtil.bufferToHex(
+                valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES),
+            );
+            this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector
+        } else {
+            this._selector = '0x';
+            this._value = valueBuf;
+        }
+
+        this._scopes = new Queue<number>();
+        this._scopes.push(RawCalldata._INITIAL_OFFSET);
+        this._offset = RawCalldata._INITIAL_OFFSET;
+    }
+
+    public popBytes(lengthInBytes: number): Buffer {
+        const value = this._value.slice(this._offset, this._offset + lengthInBytes);
+        this.setOffset(this._offset + lengthInBytes);
+        return value;
+    }
+
+    public popWord(): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(wordInBytes);
+    }
+
+    public popWords(length: number): Buffer {
+        const wordInBytes = 32;
+        return this.popBytes(length * wordInBytes);
+    }
+
+    public readBytes(from: number, to: number): Buffer {
+        const value = this._value.slice(from, to);
+        return value;
+    }
+
+    public setOffset(offsetInBytes: number): void {
+        this._offset = offsetInBytes;
+    }
+
+    public startScope(): void {
+        this._scopes.pushFront(this._offset);
+    }
+
+    public endScope(): void {
+        this._scopes.pop();
+    }
+
+    public getOffset(): number {
+        return this._offset;
+    }
+
+    public toAbsoluteOffset(relativeOffset: number): number {
+        const scopeOffset = this._scopes.peek();
+        if (scopeOffset === undefined) {
+            throw new Error(`Tried to access undefined scope.`);
+        }
+        const absoluteOffset = relativeOffset + scopeOffset;
+        return absoluteOffset;
+    }
+
+    public getSelector(): string {
+        return this._selector;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 9890619e5..0fbb9165a 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -9,14 +9,14 @@ import * as Constants from './constants';
 import {
     Calldata,
     CalldataBlock,
-    DecodingRules,
     DependentCalldataBlock,
-    EncodingRules,
     MemberCalldataBlock,
     PayloadCalldataBlock,
     RawCalldata,
 } from './calldata';
 
+import { DecodingRules, EncodingRules } from './utils/rules';
+
 export interface DataTypeFactory {
     create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
     mapDataItemToDataType: (dataItem: DataItem) => DataType;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index e8e717bf1..c4e6ee93a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -2,9 +2,10 @@ import { DataItem, MethodAbi } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { DecodingRules, EncodingRules, RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
 import { DataType, DataTypeFactory, MemberDataType } from '../data_type';
+import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { StaticBytes } from './static_bytes';
 import { Tuple } from './tuple';
diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts
index a62569fab..ea037b40a 100644
--- a/packages/utils/src/abi_encoder/index.ts
+++ b/packages/utils/src/abi_encoder/index.ts
@@ -1,2 +1,2 @@
-export { EncodingRules, DecodingRules } from './calldata';
+export { EncodingRules, DecodingRules } from './utils/rules';
 export * from './evm_data_type_factory';
diff --git a/packages/utils/src/abi_encoder/utils/queue.ts b/packages/utils/src/abi_encoder/utils/queue.ts
new file mode 100644
index 000000000..2e27afd45
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/queue.ts
@@ -0,0 +1,39 @@
+export class Queue<T> {
+    private _store: T[] = [];
+
+    public push(val: T): void {
+        this._store.push(val);
+    }
+
+    public pushFront(val: T): void {
+        this._store.unshift(val);
+    }
+
+    public pop(): T | undefined {
+        return this._store.shift();
+    }
+
+    public popBack(): T | undefined {
+        if (this._store.length === 0) {
+            return undefined;
+        }
+        const backElement = this._store.splice(-1, 1)[0];
+        return backElement;
+    }
+
+    public merge(q: Queue<T>): void {
+        this._store = this._store.concat(q._store);
+    }
+
+    public mergeFront(q: Queue<T>): void {
+        this._store = q._store.concat(this._store);
+    }
+
+    public getStore(): T[] {
+        return this._store;
+    }
+
+    public peek(): T | undefined {
+        return this._store.length >= 0 ? this._store[0] : undefined;
+    }
+}
\ No newline at end of file
diff --git a/packages/utils/src/abi_encoder/utils/rules.ts b/packages/utils/src/abi_encoder/utils/rules.ts
new file mode 100644
index 000000000..cf97ef6da
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/rules.ts
@@ -0,0 +1,8 @@
+export interface DecodingRules {
+    structsAsObjects: boolean;
+}
+
+export interface EncodingRules {
+    optimize?: boolean;
+    annotate?: boolean;
+}
\ No newline at end of file
-- 
cgit v1.2.3


From d4d917f350fb6916df50f3aa5cf09ce68b316aa1 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 13:25:49 -0800
Subject: Ran prettier

---
 packages/utils/src/abi_encoder/calldata/calldata.ts                 | 1 -
 packages/utils/src/abi_encoder/calldata/calldata_blocks.ts          | 2 +-
 packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts | 2 +-
 packages/utils/src/abi_encoder/calldata/index.ts                    | 2 +-
 packages/utils/src/abi_encoder/calldata/member_calldata_block.ts    | 2 +-
 packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts   | 2 +-
 packages/utils/src/abi_encoder/calldata/raw_calldata.ts             | 2 +-
 packages/utils/src/abi_encoder/evm_data_type_factory.ts             | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/address.ts            | 2 +-
 packages/utils/src/abi_encoder/utils/queue.ts                       | 2 +-
 packages/utils/src/abi_encoder/utils/rules.ts                       | 2 +-
 11 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 5ac4c1fe7..1abf1b681 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -1,4 +1,3 @@
-
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
index 37660ef21..8d4e7d7ca 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
@@ -1,3 +1,3 @@
 export * from './dependent_calldata_block';
 export * from './member_calldata_block';
-export * from './payload_calldata_block';
\ No newline at end of file
+export * from './payload_calldata_block';
diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
index d6870ec0b..4aec5eabc 100644
--- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
+++ b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
@@ -56,4 +56,4 @@ export class DependentCalldataBlock extends CalldataBlock {
         const rawData = Buffer.concat(rawDataComponents);
         return rawData;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts
index 0e1f57a2d..2c786cd8d 100644
--- a/packages/utils/src/abi_encoder/calldata/index.ts
+++ b/packages/utils/src/abi_encoder/calldata/index.ts
@@ -3,4 +3,4 @@ export * from './dependent_calldata_block';
 export * from './payload_calldata_block';
 export * from './member_calldata_block';
 export * from './calldata';
-export * from './raw_calldata';
\ No newline at end of file
+export * from './raw_calldata';
diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
index e9bcb2f34..c35beb8de 100644
--- a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
+++ b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
@@ -45,4 +45,4 @@ export class MemberCalldataBlock extends CalldataBlock {
     public getMembers(): CalldataBlock[] {
         return this._members;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
index 81a88bc19..0420b01d8 100644
--- a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
+++ b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
@@ -17,4 +17,4 @@ export class PayloadCalldataBlock extends CalldataBlock {
     public getRawData(): Buffer {
         return this._payload;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index 8b946ee4b..b7bd35737 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -79,4 +79,4 @@ export class RawCalldata {
     public getSelector(): string {
         return this._selector;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index 0f8dfb4a3..a3e1d404e 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -120,5 +120,5 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         return pointer;
     }
 
-    private constructor() { }
+    private constructor() {}
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 4bd992cab..3e2c9e78c 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -13,7 +13,7 @@ export class Address extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
-        Address._ADDRESS_SIZE_IN_BYTES;
+    Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
         return type === 'address';
diff --git a/packages/utils/src/abi_encoder/utils/queue.ts b/packages/utils/src/abi_encoder/utils/queue.ts
index 2e27afd45..3309d8ba2 100644
--- a/packages/utils/src/abi_encoder/utils/queue.ts
+++ b/packages/utils/src/abi_encoder/utils/queue.ts
@@ -36,4 +36,4 @@ export class Queue<T> {
     public peek(): T | undefined {
         return this._store.length >= 0 ? this._store[0] : undefined;
     }
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/abi_encoder/utils/rules.ts b/packages/utils/src/abi_encoder/utils/rules.ts
index cf97ef6da..31471e97a 100644
--- a/packages/utils/src/abi_encoder/utils/rules.ts
+++ b/packages/utils/src/abi_encoder/utils/rules.ts
@@ -5,4 +5,4 @@ export interface DecodingRules {
 export interface EncodingRules {
     optimize?: boolean;
     annotate?: boolean;
-}
\ No newline at end of file
+}
-- 
cgit v1.2.3


From a47901370bc69d6247e941c569bc9fe824516db9 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 13:40:26 -0800
Subject: Ran prettier

---
 packages/utils/src/abi_encoder/data_type.ts        | 361 ---------------------
 .../utils/src/abi_encoder/evm_data_type_factory.ts |   2 +-
 .../src/abi_encoder/evm_data_types/address.ts      |   4 +-
 .../utils/src/abi_encoder/evm_data_types/array.ts  |   2 +-
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |   2 +-
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    |   2 +-
 .../utils/src/abi_encoder/evm_data_types/int.ts    |   2 +-
 .../utils/src/abi_encoder/evm_data_types/method.ts |   2 +-
 .../utils/src/abi_encoder/evm_data_types/number.ts |   2 +-
 .../src/abi_encoder/evm_data_types/pointer.ts      |   2 +-
 .../src/abi_encoder/evm_data_types/static_bytes.ts |   4 +-
 .../utils/src/abi_encoder/evm_data_types/string.ts |   2 +-
 .../utils/src/abi_encoder/evm_data_types/tuple.ts  |   2 +-
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |   2 +-
 14 files changed, 15 insertions(+), 376 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/data_type.ts

diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
deleted file mode 100644
index 0fbb9165a..000000000
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ /dev/null
@@ -1,361 +0,0 @@
-import { DataItem } from 'ethereum-types';
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-import { BigNumber } from '../configured_bignumber';
-
-import * as Constants from './constants';
-
-import {
-    Calldata,
-    CalldataBlock,
-    DependentCalldataBlock,
-    MemberCalldataBlock,
-    PayloadCalldataBlock,
-    RawCalldata,
-} from './calldata';
-
-import { DecodingRules, EncodingRules } from './utils/rules';
-
-export interface DataTypeFactory {
-    create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
-    mapDataItemToDataType: (dataItem: DataItem) => DataType;
-}
-
-export interface DataTypeStaticInterface {
-    matchType: (type: string) => boolean;
-    encodeValue: (value: any) => Buffer;
-    decodeValue: (rawCalldata: RawCalldata) => any;
-}
-
-export abstract class DataType {
-    private static readonly _DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
-    private static readonly _DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
-    private readonly _dataItem: DataItem;
-    private readonly _factory: DataTypeFactory;
-
-    constructor(dataItem: DataItem, factory: DataTypeFactory) {
-        this._dataItem = dataItem;
-        this._factory = factory;
-    }
-
-    public getDataItem(): DataItem {
-        return this._dataItem;
-    }
-
-    public getFactory(): DataTypeFactory {
-        return this._factory;
-    }
-
-    public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = rules ? rules : DataType._DEFAULT_ENCODING_RULES;
-        const calldata = new Calldata(rules_);
-        if (selector) {
-            calldata.setSelector(selector);
-        }
-        const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block); // @TODO CHANGE
-        const calldataHex = calldata.toHexString();
-        return calldataHex;
-    }
-
-    public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
-        const rawCalldata = new RawCalldata(calldata, hasSelector);
-        const rules_ = rules ? rules : DataType._DEFAULT_DECODING_RULES;
-        const value = this.generateValue(rawCalldata, rules_);
-        return value;
-    }
-
-    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
-    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
-    public abstract getSignature(): string;
-    public abstract isStatic(): boolean;
-}
-
-export abstract class PayloadDataType extends DataType {
-    protected _hasConstantSize: boolean;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
-        super(dataItem, factory);
-        this._hasConstantSize = hasConstantSize;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
-        const encodedValue = this.encodeValue(value);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const value = this.decodeValue(calldata);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        return this._hasConstantSize;
-    }
-
-    public abstract encodeValue(value: any): Buffer;
-    public abstract decodeValue(calldata: RawCalldata): any;
-}
-
-export abstract class DependentDataType extends DataType {
-    protected _dependency: DataType;
-    protected _parent: DataType;
-    private readonly _isStatic: boolean;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
-        super(dataItem, factory);
-        this._dependency = dependency;
-        this._parent = parent;
-        this._isStatic = true;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
-        if (parentBlock === undefined) {
-            throw new Error(`DependentDataType requires a parent block to generate its block`);
-        }
-        const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const destinationOffsetBuf = calldata.popWord();
-        const currentOffset = calldata.getOffset();
-        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), Constants.HEX_BASE);
-        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
-        calldata.setOffset(destinationOffsetAbsolute);
-        const value = this._dependency.generateValue(calldata, rules);
-        calldata.setOffset(currentOffset);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        return this._isStatic;
-    }
-}
-
-export interface MemberMap {
-    [key: string]: number;
-}
-
-export abstract class MemberDataType extends DataType {
-    protected readonly _arrayLength: number | undefined;
-    protected readonly _arrayElementType: string | undefined;
-    private readonly _memberMap: MemberMap;
-    private readonly _members: DataType[];
-    private readonly _isArray: boolean;
-
-    public constructor(
-        dataItem: DataItem,
-        factory: DataTypeFactory,
-        isArray: boolean = false,
-        arrayLength?: number,
-        arrayElementType?: string,
-    ) {
-        super(dataItem, factory);
-        this._memberMap = {};
-        this._members = [];
-        this._isArray = isArray;
-        this._arrayLength = arrayLength;
-        this._arrayElementType = arrayElementType;
-        if (isArray && arrayLength !== undefined) {
-            [this._members, this._memberMap] = this._createMembersWithLength(dataItem, arrayLength);
-        } else if (!isArray) {
-            [this._members, this._memberMap] = this._createMembersWithKeys(dataItem);
-        }
-    }
-
-    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block =
-            value instanceof Array
-                ? this._generateCalldataBlockFromArray(value, parentBlock)
-                : this._generateCalldataBlockFromObject(value, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
-        let members = this._members;
-        if (this._isArray && this._arrayLength === undefined) {
-            const arrayLengthBuf = calldata.popWord();
-            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const hexBase = 16;
-            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
-            [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
-        }
-
-        calldata.startScope();
-        let value: any[] | object;
-        if (rules.structsAsObjects && !this._isArray) {
-            value = {};
-            _.each(this._memberMap, (idx: number, key: string) => {
-                const member = this._members[idx];
-                const memberValue = member.generateValue(calldata, rules);
-                (value as { [key: string]: any })[key] = memberValue;
-            });
-        } else {
-            value = [];
-            _.each(members, (member: DataType, idx: number) => {
-                const memberValue = member.generateValue(calldata, rules);
-                (value as any[]).push(memberValue);
-            });
-        }
-        calldata.endScope();
-        return value;
-    }
-
-    public isStatic(): boolean {
-        /* For Tuple:
-                    const isStaticTuple = this.children.length === 0;
-                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
-           For Array:
-                if isLengthDefined = false then this is false
-
-                Otherwise if the first element is a Pointer then false
-        */
-
-        if (this._isArray && this._arrayLength === undefined) {
-            return false;
-        }
-
-        // Search for dependent members
-        const dependentMember = _.find(this._members, (member: DataType) => {
-            return member instanceof DependentDataType;
-        });
-        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
-        return isStatic;
-    }
-
-    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
-        // Sanity check length
-        if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
-            throw new Error(
-                `Expected array of ${JSON.stringify(
-                    this._arrayLength,
-                )} elements, but got array of length ${JSON.stringify(value.length)}`,
-            );
-        }
-
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
-            this.getDataItem().name,
-            this.getSignature(),
-            parentName,
-        );
-
-        let members = this._members;
-        if (this._isArray && this._arrayLength === undefined) {
-            [members] = this._createMembersWithLength(this.getDataItem(), value.length);
-
-            const lenBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
-                Constants.EVM_WORD_WIDTH_IN_BYTES,
-            );
-            methodBlock.setHeader(lenBuf);
-        }
-
-        const memberBlocks: CalldataBlock[] = [];
-        _.each(members, (member: DataType, idx: number) => {
-            const block = member.generateCalldataBlock(value[idx], methodBlock);
-            memberBlocks.push(block);
-        });
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
-            this.getDataItem().name,
-            this.getSignature(),
-            parentName,
-        );
-        const memberBlocks: CalldataBlock[] = [];
-        const childMap = _.cloneDeep(this._memberMap);
-        _.forOwn(obj, (value: any, key: string) => {
-            if (!(key in childMap)) {
-                throw new Error(
-                    `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
-                );
-            }
-            const block = this._members[this._memberMap[key]].generateCalldataBlock(value, methodBlock);
-            memberBlocks.push(block);
-            delete childMap[key];
-        });
-
-        if (Object.keys(childMap).length !== 0) {
-            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
-        }
-
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    protected _computeSignatureOfMembers(): string {
-        // Compute signature of members
-        let signature = `(`;
-        _.each(this._members, (member: DataType, i: number) => {
-            signature += member.getSignature();
-            if (i < this._members.length - 1) {
-                signature += ',';
-            }
-        });
-        signature += ')';
-        return signature;
-    }
-
-    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
-        // Sanity check
-        if (dataItem.components === undefined) {
-            throw new Error(`Expected components`);
-        }
-
-        const members: DataType[] = [];
-        const memberMap: MemberMap = {};
-        _.each(dataItem.components, (memberItem: DataItem) => {
-            const childDataItem: DataItem = {
-                type: memberItem.type,
-                name: `${dataItem.name}.${memberItem.name}`,
-            };
-            const components = memberItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[memberItem.name] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberMap];
-    }
-
-    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
-        const members: DataType[] = [];
-        const memberMap: MemberMap = {};
-        const range = _.range(length);
-        _.each(range, (idx: number) => {
-            const childDataItem: DataItem = {
-                type: this._arrayElementType ? this._arrayElementType : '',
-                name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
-            };
-            const components = dataItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberMap[idx.toString(Constants.DEC_BASE)] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberMap];
-    }
-}
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index a3e1d404e..5d37acad9 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -3,7 +3,7 @@
 /* tslint:disable no-construct */
 import { DataItem, MethodAbi } from 'ethereum-types';
 
-import { DataType, DataTypeFactory } from './data_type';
+import { DataType, DataTypeFactory } from './abstract_data_types';
 import * as Impl from './evm_data_types';
 
 export class Address extends Impl.Address {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 3e2c9e78c..707e265f8 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -3,9 +3,9 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataTypeFactory, PayloadDataType } from '../data_type';
 
 export class Address extends PayloadDataType {
     public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
@@ -13,7 +13,7 @@ export class Address extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
-    Address._ADDRESS_SIZE_IN_BYTES;
+        Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
         return type === 'address';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 707af7c7e..f334282b8 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -1,7 +1,7 @@
 import { DataItem } from 'ethereum-types';
 
+import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
 import * as Constants from '../constants';
-import { DataTypeFactory, MemberDataType } from '../data_type';
 
 export class Array extends MemberDataType {
     private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index aee2727c7..4b9dd32b1 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -4,9 +4,9 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataTypeFactory, PayloadDataType } from '../data_type';
 
 export class Bool extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index 51165881a..5fca668e4 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -3,9 +3,9 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataTypeFactory, PayloadDataType } from '../data_type';
 
 export class DynamicBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index ba5b4cac9..ec41b9cfc 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -2,7 +2,7 @@
 import { DataItem } from 'ethereum-types';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory } from '../data_type';
+import { DataTypeFactory } from '../abstract_data_types';
 
 import { Number } from './number';
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index c4e6ee93a..ce33755f1 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -2,9 +2,9 @@ import { DataItem, MethodAbi } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
+import { DataType, DataTypeFactory, MemberDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataType, DataTypeFactory, MemberDataType } from '../data_type';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { StaticBytes } from './static_bytes';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/number.ts b/packages/utils/src/abi_encoder/evm_data_types/number.ts
index 17201362e..8ff5e9a6a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/number.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/number.ts
@@ -3,9 +3,9 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataTypeFactory, PayloadDataType } from '../data_type';
 
 export abstract class Number extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
index e0bd3509c..d4411df9b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -1,6 +1,6 @@
 import { DataItem } from 'ethereum-types';
 
-import { DataType, DataTypeFactory, DependentDataType } from '../data_type';
+import { DataType, DataTypeFactory, DependentDataType } from '../abstract_data_types';
 
 export class Pointer extends DependentDataType {
     constructor(destDataType: DataType, parentDataType: DataType, dataTypeFactory: DataTypeFactory) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 309dca234..90e872c78 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -2,9 +2,9 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataTypeFactory, PayloadDataType } from '../data_type';
 
 export class StaticBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
@@ -46,7 +46,7 @@ export class StaticBytes extends PayloadDataType {
         if (valueBuf.byteLength > this._width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                    valueBuf.byteLength
+                valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 96b36e735..c0bde8649 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -3,9 +3,9 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../constants';
-import { DataTypeFactory, PayloadDataType } from '../data_type';
 
 export class String extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 0db29c1eb..4a90e375a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -1,6 +1,6 @@
 import { DataItem } from 'ethereum-types';
 
-import { DataTypeFactory, MemberDataType } from '../data_type';
+import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
 
 export class Tuple extends MemberDataType {
     private readonly _tupleSignature: string;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index 86b31ab4c..ced3ef08b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -2,7 +2,7 @@
 import { DataItem } from 'ethereum-types';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory } from '../data_type';
+import { DataTypeFactory } from '../abstract_data_types';
 
 import { Number } from './number';
 
-- 
cgit v1.2.3


From fee67326adbbf745966803c935d5663c3ca7f52c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 13:40:46 -0800
Subject: Merge above

---
 .../abi_encoder/abstract_data_types/data_type.ts   |  51 +++++
 .../abstract_data_types/dependent_data_type.ts     |  50 +++++
 .../src/abi_encoder/abstract_data_types/index.ts   |   5 +
 .../abi_encoder/abstract_data_types/interfaces.ts  |  16 ++
 .../abstract_data_types/member_data_type.ts        | 230 +++++++++++++++++++++
 .../abstract_data_types/payload_data_type.ts       |  38 ++++
 6 files changed, 390 insertions(+)
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/index.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
new file mode 100644
index 000000000..a6adeb23b
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -0,0 +1,51 @@
+import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { Calldata, CalldataBlock, RawCalldata } from '../calldata';
+import { DecodingRules, EncodingRules } from '../utils/rules';
+
+import { DataTypeFactory } from './interfaces';
+
+export abstract class DataType {
+    private static readonly _DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
+    private static readonly _DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
+    private readonly _dataItem: DataItem;
+    private readonly _factory: DataTypeFactory;
+
+    constructor(dataItem: DataItem, factory: DataTypeFactory) {
+        this._dataItem = dataItem;
+        this._factory = factory;
+    }
+
+    public getDataItem(): DataItem {
+        return this._dataItem;
+    }
+
+    public getFactory(): DataTypeFactory {
+        return this._factory;
+    }
+
+    public encode(value: any, rules?: EncodingRules, selector?: string): string {
+        const rules_ = rules ? rules : DataType._DEFAULT_ENCODING_RULES;
+        const calldata = new Calldata(rules_);
+        if (selector) {
+            calldata.setSelector(selector);
+        }
+        const block = this.generateCalldataBlock(value);
+        calldata.setRoot(block); // @TODO CHANGE
+        const calldataHex = calldata.toHexString();
+        return calldataHex;
+    }
+
+    public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
+        const rawCalldata = new RawCalldata(calldata, hasSelector);
+        const rules_ = rules ? rules : DataType._DEFAULT_DECODING_RULES;
+        const value = this.generateValue(rawCalldata, rules_);
+        return value;
+    }
+
+    public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
+    public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
+    public abstract getSignature(): string;
+    public abstract isStatic(): boolean;
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
new file mode 100644
index 000000000..e9f390b22
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
@@ -0,0 +1,50 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { CalldataBlock, DependentCalldataBlock, RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DecodingRules } from '../utils/rules';
+
+import { DataType } from './data_type';
+import { DataTypeFactory } from './interfaces';
+
+export abstract class DependentDataType extends DataType {
+    protected _dependency: DataType;
+    protected _parent: DataType;
+    private readonly _isStatic: boolean;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+        super(dataItem, factory);
+        this._dependency = dependency;
+        this._parent = parent;
+        this._isStatic = true;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
+        if (parentBlock === undefined) {
+            throw new Error(`DependentDataType requires a parent block to generate its block`);
+        }
+        const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const destinationOffsetBuf = calldata.popWord();
+        const currentOffset = calldata.getOffset();
+        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), Constants.HEX_BASE);
+        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
+        calldata.setOffset(destinationOffsetAbsolute);
+        const value = this._dependency.generateValue(calldata, rules);
+        calldata.setOffset(currentOffset);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        return this._isStatic;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/index.ts
new file mode 100644
index 000000000..9ad568134
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/index.ts
@@ -0,0 +1,5 @@
+export * from './interfaces';
+export * from './data_type';
+export * from './dependent_data_type';
+export * from './member_data_type';
+export * from './payload_data_type';
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
new file mode 100644
index 000000000..2ae92659c
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
@@ -0,0 +1,16 @@
+import { DataItem } from 'ethereum-types';
+
+import { RawCalldata } from '../calldata';
+
+import { DataType } from './data_type';
+
+export interface DataTypeFactory {
+    create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
+    mapDataItemToDataType: (dataItem: DataItem) => DataType;
+}
+
+export interface DataTypeStaticInterface {
+    matchType: (type: string) => boolean;
+    encodeValue: (value: any) => Buffer;
+    decodeValue: (rawCalldata: RawCalldata) => any;
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
new file mode 100644
index 000000000..f44a6dd30
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
@@ -0,0 +1,230 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../../configured_bignumber';
+import { CalldataBlock, MemberCalldataBlock, RawCalldata } from '../calldata';
+import * as Constants from '../constants';
+import { DecodingRules } from '../utils/rules';
+
+import { DataType } from './data_type';
+import { DependentDataType } from './dependent_data_type';
+import { DataTypeFactory } from './interfaces';
+
+interface MemberMap {
+    [key: string]: number;
+}
+
+export abstract class MemberDataType extends DataType {
+    protected readonly _arrayLength: number | undefined;
+    protected readonly _arrayElementType: string | undefined;
+    private readonly _memberMap: MemberMap;
+    private readonly _members: DataType[];
+    private readonly _isArray: boolean;
+
+    public constructor(
+        dataItem: DataItem,
+        factory: DataTypeFactory,
+        isArray: boolean = false,
+        arrayLength?: number,
+        arrayElementType?: string,
+    ) {
+        super(dataItem, factory);
+        this._memberMap = {};
+        this._members = [];
+        this._isArray = isArray;
+        this._arrayLength = arrayLength;
+        this._arrayElementType = arrayElementType;
+        if (isArray && arrayLength !== undefined) {
+            [this._members, this._memberMap] = this._createMembersWithLength(dataItem, arrayLength);
+        } else if (!isArray) {
+            [this._members, this._memberMap] = this._createMembersWithKeys(dataItem);
+        }
+    }
+
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const block =
+            value instanceof Array
+                ? this._generateCalldataBlockFromArray(value, parentBlock)
+                : this._generateCalldataBlockFromObject(value, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
+        let members = this._members;
+        if (this._isArray && this._arrayLength === undefined) {
+            const arrayLengthBuf = calldata.popWord();
+            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+            const hexBase = 16;
+            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
+
+            [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+        }
+
+        calldata.startScope();
+        let value: any[] | object;
+        if (rules.structsAsObjects && !this._isArray) {
+            value = {};
+            _.each(this._memberMap, (idx: number, key: string) => {
+                const member = this._members[idx];
+                const memberValue = member.generateValue(calldata, rules);
+                (value as { [key: string]: any })[key] = memberValue;
+            });
+        } else {
+            value = [];
+            _.each(members, (member: DataType, idx: number) => {
+                const memberValue = member.generateValue(calldata, rules);
+                (value as any[]).push(memberValue);
+            });
+        }
+        calldata.endScope();
+        return value;
+    }
+
+    public isStatic(): boolean {
+        /* For Tuple:
+                    const isStaticTuple = this.children.length === 0;
+                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
+
+           For Array:
+                if isLengthDefined = false then this is false
+
+                Otherwise if the first element is a Pointer then false
+        */
+
+        if (this._isArray && this._arrayLength === undefined) {
+            return false;
+        }
+
+        // Search for dependent members
+        const dependentMember = _.find(this._members, (member: DataType) => {
+            return member instanceof DependentDataType;
+        });
+        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
+        return isStatic;
+    }
+
+    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
+        // Sanity check length
+        if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
+            throw new Error(
+                `Expected array of ${JSON.stringify(
+                    this._arrayLength,
+                )} elements, but got array of length ${JSON.stringify(value.length)}`,
+            );
+        }
+
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
+            this.getDataItem().name,
+            this.getSignature(),
+            parentName,
+        );
+
+        let members = this._members;
+        if (this._isArray && this._arrayLength === undefined) {
+            [members] = this._createMembersWithLength(this.getDataItem(), value.length);
+
+            const lenBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
+                Constants.EVM_WORD_WIDTH_IN_BYTES,
+            );
+            methodBlock.setHeader(lenBuf);
+        }
+
+        const memberBlocks: CalldataBlock[] = [];
+        _.each(members, (member: DataType, idx: number) => {
+            const block = member.generateCalldataBlock(value[idx], methodBlock);
+            memberBlocks.push(block);
+        });
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
+    }
+
+    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
+            this.getDataItem().name,
+            this.getSignature(),
+            parentName,
+        );
+        const memberBlocks: CalldataBlock[] = [];
+        const childMap = _.cloneDeep(this._memberMap);
+        _.forOwn(obj, (value: any, key: string) => {
+            if (!(key in childMap)) {
+                throw new Error(
+                    `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
+                );
+            }
+            const block = this._members[this._memberMap[key]].generateCalldataBlock(value, methodBlock);
+            memberBlocks.push(block);
+            delete childMap[key];
+        });
+
+        if (Object.keys(childMap).length !== 0) {
+            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+        }
+
+        methodBlock.setMembers(memberBlocks);
+        return methodBlock;
+    }
+
+    protected _computeSignatureOfMembers(): string {
+        // Compute signature of members
+        let signature = `(`;
+        _.each(this._members, (member: DataType, i: number) => {
+            signature += member.getSignature();
+            if (i < this._members.length - 1) {
+                signature += ',';
+            }
+        });
+        signature += ')';
+        return signature;
+    }
+
+    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+        // Sanity check
+        if (dataItem.components === undefined) {
+            throw new Error(`Expected components`);
+        }
+
+        const members: DataType[] = [];
+        const memberMap: MemberMap = {};
+        _.each(dataItem.components, (memberItem: DataItem) => {
+            const childDataItem: DataItem = {
+                type: memberItem.type,
+                name: `${dataItem.name}.${memberItem.name}`,
+            };
+            const components = memberItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[memberItem.name] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberMap];
+    }
+
+    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+        const members: DataType[] = [];
+        const memberMap: MemberMap = {};
+        const range = _.range(length);
+        _.each(range, (idx: number) => {
+            const childDataItem: DataItem = {
+                type: this._arrayElementType ? this._arrayElementType : '',
+                name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
+            };
+            const components = dataItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberMap[idx.toString(Constants.DEC_BASE)] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberMap];
+    }
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
new file mode 100644
index 000000000..767e64f51
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
@@ -0,0 +1,38 @@
+import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { CalldataBlock, PayloadCalldataBlock, RawCalldata } from '../calldata';
+import { DecodingRules } from '../utils/rules';
+
+import { DataType } from './data_type';
+import { DataTypeFactory } from './interfaces';
+
+export abstract class PayloadDataType extends DataType {
+    protected _hasConstantSize: boolean;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+        super(dataItem, factory);
+        this._hasConstantSize = hasConstantSize;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
+        const encodedValue = this.encodeValue(value);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const value = this.decodeValue(calldata);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        return this._hasConstantSize;
+    }
+
+    public abstract encodeValue(value: any): Buffer;
+    public abstract decodeValue(calldata: RawCalldata): any;
+}
-- 
cgit v1.2.3


From 5a748fb4e5ce9603cf100af5d46c323934ab17ad Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 13:56:37 -0800
Subject: Split ABI Encoder/Decoder tests into separate files

---
 .../src/abi_encoder/evm_data_types/address.ts      |    2 +-
 .../src/abi_encoder/evm_data_types/static_bytes.ts |    2 +-
 .../test/abi_encoder/abi_samples/method_abis.ts    |  780 +++++++++
 .../test/abi_encoder/abi_samples/optimizer_abis.ts |  340 ++++
 .../abi_encoder/abi_samples/return_value_abis.ts   |   99 ++
 .../utils/test/abi_encoder/evm_data_types_test.ts  | 1094 ++++++++++++
 packages/utils/test/abi_encoder/methods_test.ts    |  401 +++++
 packages/utils/test/abi_encoder/optimizer_test.ts  |  293 ++++
 .../utils/test/abi_encoder/return_values_test.ts   |   78 +
 packages/utils/test/abi_encoder_test.ts            | 1852 --------------------
 packages/utils/test/abi_samples.ts                 |  780 ---------
 packages/utils/test/optimizer_abis.ts              |  340 ----
 packages/utils/test/return_value_abis.ts           |   99 --
 13 files changed, 3087 insertions(+), 3073 deletions(-)
 create mode 100644 packages/utils/test/abi_encoder/abi_samples/method_abis.ts
 create mode 100644 packages/utils/test/abi_encoder/abi_samples/optimizer_abis.ts
 create mode 100644 packages/utils/test/abi_encoder/abi_samples/return_value_abis.ts
 create mode 100644 packages/utils/test/abi_encoder/evm_data_types_test.ts
 create mode 100644 packages/utils/test/abi_encoder/methods_test.ts
 create mode 100644 packages/utils/test/abi_encoder/optimizer_test.ts
 create mode 100644 packages/utils/test/abi_encoder/return_values_test.ts
 delete mode 100644 packages/utils/test/abi_encoder_test.ts
 delete mode 100644 packages/utils/test/abi_samples.ts
 delete mode 100644 packages/utils/test/optimizer_abis.ts
 delete mode 100644 packages/utils/test/return_value_abis.ts

diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 707e265f8..0107fdc50 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -13,7 +13,7 @@ export class Address extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
-        Address._ADDRESS_SIZE_IN_BYTES;
+    Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
         return type === 'address';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 90e872c78..4e49db609 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -46,7 +46,7 @@ export class StaticBytes extends PayloadDataType {
         if (valueBuf.byteLength > this._width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                valueBuf.byteLength
+                    valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
diff --git a/packages/utils/test/abi_encoder/abi_samples/method_abis.ts b/packages/utils/test/abi_encoder/abi_samples/method_abis.ts
new file mode 100644
index 000000000..fc552c127
--- /dev/null
+++ b/packages/utils/test/abi_encoder/abi_samples/method_abis.ts
@@ -0,0 +1,780 @@
+/* tslint:disable max-file-line-count */
+import { MethodAbi } from 'ethereum-types';
+
+export const simpleAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'uint256',
+        },
+        {
+            name: 'gregStr',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const stringAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'greg',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const GAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'a',
+                    type: 'uint256',
+                },
+                {
+                    name: 'b',
+                    type: 'string',
+                },
+                {
+                    name: 'e',
+                    type: 'bytes',
+                },
+                {
+                    name: 'f',
+                    type: 'address',
+                },
+            ],
+
+            name: 'f',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const typesWithDefaultWidthsAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someUint',
+            type: 'uint',
+        },
+        {
+            name: 'someInt',
+            type: 'int',
+        },
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someUint',
+            type: 'uint[]',
+        },
+        {
+            name: 'someInt',
+            type: 'int[]',
+        },
+        {
+            name: 'someByte',
+            type: 'byte[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const multiDimensionalArraysStaticTypeAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'a',
+            type: 'uint8[][][]',
+        },
+        {
+            name: 'b',
+            type: 'uint8[][][2]',
+        },
+        {
+            name: 'c',
+            type: 'uint8[][2][]',
+        },
+        {
+            name: 'd',
+            type: 'uint8[2][][]',
+        },
+        {
+            name: 'e',
+            type: 'uint8[][2][2]',
+        },
+        {
+            name: 'f',
+            type: 'uint8[2][2][]',
+        },
+        {
+            name: 'g',
+            type: 'uint8[2][][2]',
+        },
+        {
+            name: 'h',
+            type: 'uint8[2][2][2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const multiDimensionalArraysDynamicTypeAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'a',
+            type: 'string[][][]',
+        },
+        {
+            name: 'b',
+            type: 'string[][][2]',
+        },
+        {
+            name: 'c',
+            type: 'string[][2][]',
+        },
+        {
+            name: 'h',
+            type: 'string[2][2][2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const dynamicTupleAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayOfStaticTuplesWithDefinedLengthAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[8]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayOfStaticTuplesWithDynamicLengthAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayOfDynamicTuplesWithDefinedLengthAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[8]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayOfDynamicTuplesWithUndefinedLengthAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayOfDynamicTuplesAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const multidimensionalArrayOfDynamicTuplesAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someString',
+                    type: 'string',
+                },
+            ],
+            name: 'order',
+            type: 'tuple[][2][]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const staticTupleAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'someUint1',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint2',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someUint3',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someBool',
+                    type: 'bool',
+                },
+            ],
+            name: 'order',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const staticArrayAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const staticArrayDynamicMembersAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'string[3]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const dynamicArrayDynamicMembersAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const dynamicArrayStaticMembersAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const largeFlatAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someUInt256',
+            type: 'uint256',
+        },
+        {
+            name: 'someInt256',
+            type: 'int256',
+        },
+        {
+            name: 'someInt32',
+            type: 'int32',
+        },
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+        {
+            name: 'someAddress',
+            type: 'address',
+        },
+        {
+            name: 'someBool',
+            type: 'bool',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const largeNestedAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someStaticArray',
+            type: 'uint8[3]',
+        },
+        {
+            name: 'someStaticArrayWithDynamicMembers',
+            type: 'string[2]',
+        },
+        {
+            name: 'someDynamicArrayWithDynamicMembers',
+            type: 'bytes[]',
+        },
+        {
+            name: 'some2DArray',
+            type: 'string[][]',
+        },
+        {
+            name: 'someTuple',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+            ],
+        },
+        {
+            name: 'someTupleWithDynamicTypes',
+            type: 'tuple',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                /*{
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },*/
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        },
+        {
+            name: 'someArrayOfTuplesWithDynamicTypes',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                /*{
+                    name: 'someStrArray',
+                    type: 'string[]',
+                },*/
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const nestedTuples: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'firstTuple',
+            type: 'tuple[1]',
+            components: [
+                {
+                    name: 'someUint32',
+                    type: 'uint32',
+                },
+                {
+                    name: 'nestedTuple',
+                    type: 'tuple',
+                    components: [
+                        {
+                            name: 'someUint',
+                            type: 'uint256',
+                        },
+                        {
+                            name: 'someAddress',
+                            type: 'address',
+                        },
+                    ],
+                },
+            ],
+        },
+        {
+            name: 'secondTuple',
+            type: 'tuple[]',
+            components: [
+                {
+                    name: 'someUint',
+                    type: 'uint256',
+                },
+                {
+                    name: 'someStr',
+                    type: 'string',
+                },
+                {
+                    name: 'nestedTuple',
+                    type: 'tuple',
+                    components: [
+                        {
+                            name: 'someUint32',
+                            type: 'uint32',
+                        },
+                        {
+                            name: 'secondNestedTuple',
+                            type: 'tuple',
+                            components: [
+                                {
+                                    name: 'someUint',
+                                    type: 'uint256',
+                                },
+                                {
+                                    name: 'someStr',
+                                    type: 'string',
+                                },
+                                {
+                                    name: 'someBytes',
+                                    type: 'bytes',
+                                },
+                                {
+                                    name: 'someAddress',
+                                    type: 'address',
+                                },
+                            ],
+                        },
+                    ],
+                },
+                {
+                    name: 'someBytes',
+                    type: 'bytes',
+                },
+                {
+                    name: 'someAddress',
+                    type: 'address',
+                },
+            ],
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const simpleAbi2: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'someByte',
+            type: 'byte',
+        },
+        {
+            name: 'someBytes32',
+            type: 'bytes32',
+        },
+        {
+            name: 'someBytes',
+            type: 'bytes',
+        },
+        {
+            name: 'someString',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const fillOrderAbi: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            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: 'order',
+            type: 'tuple',
+        },
+        {
+            name: 'takerAssetFillAmount',
+            type: 'uint256',
+        },
+        {
+            name: 'salt',
+            type: 'uint256',
+        },
+        {
+            name: 'orderSignature',
+            type: 'bytes',
+        },
+        {
+            name: 'takerSignature',
+            type: 'bytes',
+        },
+    ],
+    name: 'fillOrder',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
diff --git a/packages/utils/test/abi_encoder/abi_samples/optimizer_abis.ts b/packages/utils/test/abi_encoder/abi_samples/optimizer_abis.ts
new file mode 100644
index 000000000..7cfd7a118
--- /dev/null
+++ b/packages/utils/test/abi_encoder/abi_samples/optimizer_abis.ts
@@ -0,0 +1,340 @@
+/* tslint:disable max-file-line-count */
+import { MethodAbi } from 'ethereum-types';
+
+export const duplicateDynamicArraysWithStaticElements: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'uint[]',
+        },
+        {
+            name: 'array2',
+            type: 'uint[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateDynamicArraysWithDynamicElements: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'string[]',
+        },
+        {
+            name: 'array2',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateStaticArraysWithStaticElements: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'uint[2]',
+        },
+        {
+            name: 'array2',
+            type: 'uint[2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateStaticArraysWithDynamicElements: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'string[2]',
+        },
+        {
+            name: 'array2',
+            type: 'string[2]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateArrayElements: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array',
+            type: 'string[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateTupleFields: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'field1',
+                    type: 'string',
+                },
+                {
+                    name: 'field2',
+                    type: 'string',
+                },
+            ],
+            name: 'Tuple',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateStrings: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'string1',
+            type: 'string',
+        },
+        {
+            name: 'string2',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateBytes: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'bytes1',
+            type: 'bytes',
+        },
+        {
+            name: 'bytes2',
+            type: 'bytes',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateTuples: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'field1',
+                    type: 'string',
+                },
+                {
+                    name: 'field2',
+                    type: 'uint',
+                },
+            ],
+            name: 'Tuple',
+            type: 'tuple',
+        },
+        {
+            components: [
+                {
+                    name: 'field1',
+                    type: 'string',
+                },
+                {
+                    name: 'field2',
+                    type: 'uint',
+                },
+            ],
+            name: 'Tuple',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateArraysNestedInTuples: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    name: 'field',
+                    type: 'uint[]',
+                },
+            ],
+            name: 'Tuple1',
+            type: 'tuple',
+        },
+        {
+            components: [
+                {
+                    name: 'field',
+                    type: 'uint[]',
+                },
+                {
+                    name: 'extraField',
+                    type: 'string',
+                },
+            ],
+            name: 'Tuple2',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateTuplesNestedInTuples: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            components: [
+                {
+                    components: [
+                        {
+                            name: 'nestedField',
+                            type: 'string',
+                        },
+                    ],
+                    name: 'field',
+                    type: 'tuple',
+                },
+            ],
+            name: 'Tuple1',
+            type: 'tuple',
+        },
+        {
+            components: [
+                {
+                    components: [
+                        {
+                            name: 'nestedField',
+                            type: 'string',
+                        },
+                    ],
+                    name: 'field',
+                    type: 'tuple',
+                },
+                {
+                    name: 'extraField',
+                    type: 'string',
+                },
+            ],
+            name: 'Tuple1',
+            type: 'tuple',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const duplicateTwoDimensionalArrays: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'array1',
+            type: 'string[][]',
+        },
+        {
+            name: 'array2',
+            type: 'string[][]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayElementsDuplicatedAsSeparateParameter: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'stringArray',
+            type: 'string[]',
+        },
+        {
+            name: 'string',
+            type: 'string',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const arrayElementsDuplicatedAsTupleFields: MethodAbi = {
+    constant: false,
+    inputs: [
+        {
+            name: 'uint8Array',
+            type: 'uint8[]',
+        },
+        {
+            components: [
+                {
+                    name: 'uint',
+                    type: 'uint',
+                },
+            ],
+            name: 'uintTuple',
+            type: 'tuple[]',
+        },
+    ],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
diff --git a/packages/utils/test/abi_encoder/abi_samples/return_value_abis.ts b/packages/utils/test/abi_encoder/abi_samples/return_value_abis.ts
new file mode 100644
index 000000000..ac2124011
--- /dev/null
+++ b/packages/utils/test/abi_encoder/abi_samples/return_value_abis.ts
@@ -0,0 +1,99 @@
+/* tslint:disable max-file-line-count */
+import { MethodAbi } from 'ethereum-types';
+
+export const noReturnValues: MethodAbi = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const singleStaticReturnValue: MethodAbi = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'Bytes4',
+            type: 'bytes4',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const multipleStaticReturnValues: MethodAbi = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val1',
+            type: 'bytes4',
+        },
+        {
+            name: 'val2',
+            type: 'bytes4',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const singleDynamicReturnValue: MethodAbi = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val',
+            type: 'bytes',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const multipleDynamicReturnValues: MethodAbi = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val1',
+            type: 'bytes',
+        },
+        {
+            name: 'val2',
+            type: 'bytes',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
+
+export const mixedStaticAndDynamicReturnValues: MethodAbi = {
+    constant: false,
+    inputs: [],
+    name: 'simpleFunction',
+    outputs: [
+        {
+            name: 'val1',
+            type: 'bytes4',
+        },
+        {
+            name: 'val2',
+            type: 'bytes',
+        },
+    ],
+    payable: false,
+    stateMutability: 'nonpayable',
+    type: 'function',
+};
diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts
new file mode 100644
index 000000000..9c3e3c0f9
--- /dev/null
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -0,0 +1,1094 @@
+/* tslint:disable max-file-line-count */
+import * as chai from 'chai';
+import * as ethUtil from 'ethereumjs-util';
+import 'mocha';
+
+import { AbiEncoder, BigNumber } from '../../src/';
+import { chaiSetup } from '../utils/chai_setup';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
+    describe('Array', () => {
+        it('Fixed size; Static elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'int[2]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = [new BigNumber(5), new BigNumber(6)];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Dynamic size; Static elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'int[]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = [new BigNumber(5), new BigNumber(6)];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Fixed size; Dynamic elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[2]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = ['Hello', 'world'];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Dynamic size; Dynamic elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = ['Hello', 'world'];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Dynamic Size; Multidimensional; Dynamic Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes[][]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617'];
+            const array3 = ['0x18192021'];
+            const args = [array1, array2, array3];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000041011121300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414151617000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Dynamic Size; Multidimensional; Static Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes4[][]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617'];
+            const array3 = ['0x18192021'];
+            const args = [array1, array2, array3];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000301020304000000000000000000000000000000000000000000000000000000000506070800000000000000000000000000000000000000000000000000000000091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021011121300000000000000000000000000000000000000000000000000000000141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Static Size; Multidimensional; Static Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes4[3][2]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617', '0x18192021'];
+            const args = [array1, array2];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x010203040000000000000000000000000000000000000000000000000000000005060708000000000000000000000000000000000000000000000000000000000910111200000000000000000000000000000000000000000000000000000000101112130000000000000000000000000000000000000000000000000000000014151617000000000000000000000000000000000000000000000000000000001819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Static Size; Multidimensional; Dynamic Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'bytes[3][2]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
+            const array2 = ['0x10111213', '0x14151617', '0x18192021'];
+            const args = [array1, array2];
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000401020304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040910111200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000410111213000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Static size; Too Few Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[3]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = ['Hello', 'world'];
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Expected array of 3 elements, but got array of length 2');
+        });
+        it('Static size; Too Many Elements', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'string[1]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = ['Hello', 'world'];
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Expected array of 1 elements, but got array of length 2');
+        });
+        it('Element Type Mismatch', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'testArray', type: 'uint[]' };
+            const dataType = new AbiEncoder.Array(testDataItem);
+            // Construct args to be encoded
+            const args = [new BigNumber(1), 'Bad Argument'];
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+    });
+
+    describe('Tuple', () => {
+        it('Static elements only', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: new BigNumber(-5), field_2: true };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Dynamic elements only', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'string' }, { name: 'field_2', type: 'bytes' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: 'Hello, World!', field_2: '0xabcdef0123456789' };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Static Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'uint[2]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field: [new BigNumber(1), new BigNumber(2)] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Dynamic Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'uint[]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field: [new BigNumber(1), new BigNumber(2)] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Static Multidimensional Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'bytes4[2][2]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708'];
+            const array2 = ['0x09101112', '0x13141516'];
+            const args = { field: [array1, array2] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Nested Dynamic Multidimensional Array', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field', type: 'bytes[2][2]' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const array1 = ['0x01020304', '0x05060708'];
+            const array2 = ['0x09101112', '0x13141516'];
+            const args = { field: [array1, array2] };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Static and dynamic elements mixed', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [
+                    { name: 'field_1', type: 'int32' },
+                    { name: 'field_2', type: 'string' },
+                    { name: 'field_3', type: 'bool' },
+                    { name: 'field_4', type: 'bytes' },
+                ],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = {
+                field_1: new BigNumber(-5),
+                field_2: 'Hello, World!',
+                field_3: true,
+                field_4: '0xabcdef0123456789',
+            };
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
+            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Missing Key', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { field_1: new BigNumber(-5) };
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Could not assign tuple to object: missing keys field_2');
+        });
+        it('Bad Key', async () => {
+            // Create DataType object
+            const testDataItem = {
+                name: 'Tuple',
+                type: 'tuple',
+                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
+            };
+            const dataType = new AbiEncoder.Tuple(testDataItem);
+            // Construct args to be encoded
+            const args = { unknown_field: new BigNumber(-5) };
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw("Could not assign tuple to object: unrecognized key 'unknown_field' in object Tuple");
+        });
+    });
+
+    describe('Address', () => {
+        it('Valid Address', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Address', type: 'address' };
+            const dataType = new AbiEncoder.Address(testDataItem);
+            // Construct args to be encoded
+            const args = '0xe41d2489571d322189246dafa5ebde1f4699f498';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Invalid Address - input is not valid hex', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Address', type: 'address' };
+            const dataType = new AbiEncoder.Address(testDataItem);
+            // Construct args to be encoded
+            const args = 'e4';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+        });
+        it('Invalid Address - input is not 20 bytes', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Address', type: 'address' };
+            const dataType = new AbiEncoder.Address(testDataItem);
+            // Construct args to be encoded
+            const args = '0xe4';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
+        });
+    });
+
+    describe('Bool', () => {
+        it('True', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Boolean', type: 'bool' };
+            const dataType = new AbiEncoder.Bool(testDataItem);
+            // Construct args to be encoded
+            const args = true;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('False', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Boolean', type: 'bool' };
+            const dataType = new AbiEncoder.Bool(testDataItem);
+            // Construct args to be encoded
+            const args = false;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+    });
+
+    describe('Integer', () => {
+        /* tslint:disable custom-no-magic-numbers */
+        const max256BitInteger = new BigNumber(2).pow(255).minus(1);
+        const min256BitInteger = new BigNumber(2).pow(255).times(-1);
+        const max32BitInteger = new BigNumber(2).pow(31).minus(1);
+        const min32BitInteger = new BigNumber(2).pow(31).times(-1);
+        /* tslint:enable custom-no-magic-numbers */
+
+        it('Int256 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int256 - Negative Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(-1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int256 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = max256BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int256 - Negative Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = min256BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0x8000000000000000000000000000000000000000000000000000000000000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int256 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = max256BitInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+        it('Int256 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (256)', type: 'int' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = min256BitInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+        it('Int32 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int32 - Negative Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(-1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int32 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = max32BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000007fffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int32 - Negative Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = min32BitInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Int32 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = max32BitInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+        it('Int32 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Integer (32)', type: 'int32' };
+            const dataType = new AbiEncoder.Int(testDataItem);
+            // Construct args to be encoded
+            const args = min32BitInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+    });
+
+    describe('Unsigned Integer', () => {
+        /* tslint:disable custom-no-magic-numbers */
+        const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
+        const min256BitUnsignedInteger = new BigNumber(0);
+        const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
+        const min32BitUnsignedInteger = new BigNumber(0);
+        /* tslint:enable custom-no-magic-numbers */
+
+        it('UInt256 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('UInt256 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = max256BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('UInt256 - Zero Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = min256BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('UInt256 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = max256BitUnsignedInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+        it('UInt256 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = min256BitUnsignedInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+        it('UInt32 - Positive Base Case', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = new BigNumber(1);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('UInt32 - Positive Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = max32BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000ffffffff';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('UInt32 - Zero Value', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = min32BitUnsignedInteger;
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('UInt32 - Value too large', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = max32BitUnsignedInteger.plus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+        it('UInt32 - Value too small', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
+            const dataType = new AbiEncoder.UInt(testDataItem);
+            // Construct args to be encoded
+            const args = min32BitUnsignedInteger.minus(1);
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw();
+        });
+    });
+
+    describe('Static Bytes', () => {
+        it('Single Byte (byte)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Byte', type: 'byte' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x05';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Single Byte (bytes1)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes1', type: 'bytes1' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x05';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('4 Bytes (bytes4)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x00010203';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0001020300000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('4 Bytes (bytes4); Encoder must pad input', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x1a18000000000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const paddedArgs = '0x1a180000';
+            const paddedArgsAsJson = JSON.stringify(paddedArgs);
+            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
+        });
+        it('32 Bytes (bytes32)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x0001020304050607080911121314151617181920212223242526272829303132';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x0001020304050607080911121314151617181920212223242526272829303132';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('32 Bytes (bytes32); Encoder must pad input', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18bf61';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const paddedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+            const paddedArgsAsJson = JSON.stringify(paddedArgs);
+            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
+        });
+        it('Should throw when pass in too many bytes (bytes4)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x0102030405';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(
+                'Tried to assign 0x0102030405 (5 bytes), which exceeds max bytes that can be stored in a bytes4',
+            );
+        });
+        it('Should throw when pass in too many bytes (bytes32)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x010203040506070809101112131415161718192021222324252627282930313233';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw(
+                'Tried to assign 0x010203040506070809101112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32',
+            );
+        });
+        it('Should throw when pass in bad hex (no 0x prefix)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0102030405060708091011121314151617181920212223242526272829303132';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
+        });
+        it('Should throw when pass in bad hex (include a half-byte)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
+            const dataType = new AbiEncoder.StaticBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x010';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
+        });
+    });
+
+    describe('Dynamic Bytes', () => {
+        it('Fits into one EVM word', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18bf61';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Spans multiple EVM words', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const bytesLength = 40;
+            const args = '0x' + '61'.repeat(bytesLength);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Input as Buffer', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = '0x1a18bf61';
+            const argsAsBuffer = ethUtil.toBuffer(args);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(argsAsBuffer);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Should throw when pass in bad hex (no 0x prefix)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '01';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
+        });
+        it('Should throw when pass in bad hex (include a half-byte)', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'Static Bytes', type: 'bytes' };
+            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
+            // Construct args to be encoded
+            const args = '0x010';
+            // Encode Args and validate result
+            expect(() => {
+                dataType.encode(args);
+            }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
+        });
+    });
+
+    describe('String', () => {
+        it('Fits into one EVM word', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'String', type: 'string' };
+            const dataType = new AbiEncoder.String(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const args = 'five';
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('Spans multiple EVM words', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'String', type: 'string' };
+            const dataType = new AbiEncoder.String(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const bytesLength = 40;
+            const args = 'a'.repeat(bytesLength);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+        it('String that begins with 0x prefix', async () => {
+            // Create DataType object
+            const testDataItem = { name: 'String', type: 'string' };
+            const dataType = new AbiEncoder.String(testDataItem);
+            // Construct args to be encoded
+            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
+            const strLength = 40;
+            const args = '0x' + 'a'.repeat(strLength);
+            // Encode Args and validate result
+            const encodedArgs = dataType.encode(args);
+            const expectedEncodedArgs =
+                '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
+            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+            // Decode Encoded Args and validate result
+            const decodedArgs = dataType.decode(encodedArgs);
+            const decodedArgsAsJson = JSON.stringify(decodedArgs);
+            const argsAsJson = JSON.stringify(args);
+            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+        });
+    });
+});
diff --git a/packages/utils/test/abi_encoder/methods_test.ts b/packages/utils/test/abi_encoder/methods_test.ts
new file mode 100644
index 000000000..d158b9e5b
--- /dev/null
+++ b/packages/utils/test/abi_encoder/methods_test.ts
@@ -0,0 +1,401 @@
+import * as chai from 'chai';
+import 'mocha';
+
+import { AbiEncoder, BigNumber } from '../../src/';
+import { chaiSetup } from '../utils/chai_setup';
+
+import * as AbiSamples from './abi_samples/method_abis';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('ABI Encoder: Method Encoding / Decoding', () => {
+    it('Types with default widths', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
+        const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Array of Static Tuples (Array has defined length)', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
+        let value = 0;
+        const arrayOfTuples = [];
+        const arrayOfTuplesLength = 8;
+        for (let i = 0; i < arrayOfTuplesLength; ++i) {
+            arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
+        }
+        const args = [arrayOfTuples];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Array of Static Tuples (Array has dynamic length)', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
+        let value = 0;
+        const arrayOfTuples = [];
+        const arrayOfTuplesLength = 8;
+        for (let i = 0; i < arrayOfTuplesLength; ++i) {
+            arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
+        }
+        const args = [arrayOfTuples];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Array of Dynamic Tuples (Array has defined length)', async () => {
+        // Generate Calldata
+        const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
+        let value = 0;
+        const arrayOfTuples = [];
+        const arrayOfTuplesLength = 8;
+        for (let i = 0; i < arrayOfTuplesLength; ++i) {
+            arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
+        }
+        const args = [arrayOfTuples];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
+        let value = 0;
+        const arrayOfTuples = [];
+        const arrayOfTuplesLength = 8;
+        for (let i = 0; i < arrayOfTuplesLength; ++i) {
+            arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
+        }
+        const args = [arrayOfTuples];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Multidimensional Arrays / Static Members', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
+        // Eight 3-dimensional arrays of uint8[2][2][2]
+        let value = 0;
+        const args = [];
+        const argsLength = 8;
+        for (let i = 0; i < argsLength; ++i) {
+            args.push([
+                [[new BigNumber(++value), new BigNumber(++value)], [new BigNumber(++value), new BigNumber(++value)]],
+                [[new BigNumber(++value), new BigNumber(++value)], [new BigNumber(++value), new BigNumber(++value)]],
+            ]);
+        }
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038';
+        expect(calldata).to.be.equal(expectedCalldata);
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Multidimensional Arrays / Dynamic Members', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
+        // Eight 3-dimensional arrays of string[2][2][2]
+        let value = 0;
+        const args = [];
+        const argsLength = 4;
+        for (let i = 0; i < argsLength; ++i) {
+            args.push([
+                [
+                    [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                    [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                ],
+                [
+                    [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                    [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
+                ],
+            ]);
+        }
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Fixed Length Array / Dynamic Members', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
+        const args = [['Brave', 'New', 'World']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Fixed Length Array / Dynamic Members', async () => {
+        // Generaet calldata
+        const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
+        const args = [['Brave', 'New', 'World']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Unfixed Length Array / Dynamic Members ABI', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
+        const args = [['Brave', 'New', 'World']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Unfixed Length Array / Static Members ABI', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
+        const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Fixed Length Array / Static Members ABI', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
+        const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Array ABI', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(AbiSamples.stringAbi);
+        const args = [['five', 'six', 'seven']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Static Tuple', async () => {
+        // Generate calldata
+        // This is dynamic because it has dynamic members
+        const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
+        const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Dynamic Tuple (Array input)', async () => {
+        // Generate calldata
+        // This is dynamic because it has dynamic members
+        const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
+        const args = [[new BigNumber(5), 'five']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Dynamic Tuple (Object input)', async () => {
+        // Generate Calldata
+        // This is dynamic because it has dynamic members
+        const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
+        const args = [[new BigNumber(5), 'five']];
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Large, Flat ABI', async () => {
+        // Construct calldata
+        const method = new AbiEncoder.Method(AbiSamples.largeFlatAbi);
+        const args = [
+            new BigNumber(256745454),
+            new BigNumber(-256745454),
+            new BigNumber(434244),
+            '0x43',
+            '0x0001020304050607080911121314151617181920212223242526272829303132',
+            '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
+            'Little peter piper piped a piping pepper pot',
+            '0xe41d2489571d322189246dafa5ebde1f4699f498',
+            true,
+        ];
+        // Validate calldata
+        const calldata = method.encode(args);
+        const expectedCalldata =
+            '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata);
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+    it('Large, Nested ABI', async () => {
+        // Construct Calldata
+        const method = new AbiEncoder.Method(AbiSamples.largeNestedAbi);
+        const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
+        const someStaticArrayWithDynamicMembers = [
+            'the little piping piper piped a piping pipper papper',
+            'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+        ];
+        const someDynamicArrayWithDynamicMembers = [
+            '0x38745637834987324827439287423897238947239847',
+            '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
+            '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
+        ];
+        const some2DArray = [
+            [
+                'some string',
+                'some another string',
+                'there are just too many stringsup in',
+                'here',
+                'yall ghonna make me lose my mind',
+            ],
+            [
+                'the little piping piper piped a piping pipper papper',
+                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+            ],
+            [],
+        ];
+        const someTuple = {
+            someUint32: new BigNumber(4037824789),
+            someStr:
+                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
+        };
+        const someTupleWithDynamicTypes = {
+            someUint: new BigNumber(4024789),
+            someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
+            someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
+            someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
+        };
+        const someTupleWithDynamicTypes2 = {
+            someUint: new BigNumber(9024789),
+            someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
+            someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
+            someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
+        };
+        const someTupleWithDynamicTypes3 = {
+            someUint: new BigNumber(1024789),
+            someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
+            someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
+            someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
+        };
+        const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
+        const args = {
+            someStaticArray,
+            someStaticArrayWithDynamicMembers,
+            someDynamicArrayWithDynamicMembers,
+            some2DArray,
+            someTuple,
+            someTupleWithDynamicTypes,
+            someArrayOfTuplesWithDynamicTypes,
+        };
+        const calldata = method.encode(args);
+        // Validate calldata
+        const expectedCalldata =
+            '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
+        expect(calldata).to.be.equal(expectedCalldata);
+        // Validate decoding
+        const expectedDecodedValueJson = JSON.stringify(args);
+        const decodedValue = method.decode(calldata, { structsAsObjects: true });
+        const decodedValueJson = JSON.stringify(decodedValue);
+        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+    });
+});
diff --git a/packages/utils/test/abi_encoder/optimizer_test.ts b/packages/utils/test/abi_encoder/optimizer_test.ts
new file mode 100644
index 000000000..304c9cbc2
--- /dev/null
+++ b/packages/utils/test/abi_encoder/optimizer_test.ts
@@ -0,0 +1,293 @@
+import * as chai from 'chai';
+import 'mocha';
+
+import { AbiEncoder, BigNumber } from '../../src/';
+import { chaiSetup } from '../utils/chai_setup';
+
+import * as OptimizedAbis from './abi_samples/optimizer_abis';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
+    it('Duplicate Dynamic Arrays with Static Elements', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
+        const array1 = [new BigNumber(100), new BigNumber(150)];
+        const array2 = array1;
+        const args = [array1, array2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Dynamic Arrays with Dynamic Elements', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements);
+        const array1 = ['Hello', 'World'];
+        const array2 = array1;
+        const args = [array1, array2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Static Arrays with Static Elements (should not optimize)', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithStaticElements);
+        const array1 = [new BigNumber(100), new BigNumber(150)];
+        const array2 = array1;
+        const args = [array1, array2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x7f8130430000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        const unoptimizedCalldata = method.encode(args);
+        expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Static Arrays with Dynamic Elements', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements);
+        const array1 = ['Hello', 'World'];
+        const array2 = array1;
+        const args = [array1, array2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Array Elements (should optimize)', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateArrayElements);
+        const strings = ['Hello', 'World', 'Hello', 'World'];
+        const args = [strings];
+        // Validate calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Tuple Fields', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTupleFields);
+        const tuple = ['Hello', 'Hello'];
+        const args = [tuple];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Strings', async () => {
+        // Description:
+        //   Two dynamic arrays with the same values.
+        //   In the optimized calldata, only one set of elements should be included.
+        //   Both arrays should point to this set.
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateStrings);
+        const args = ['Hello', 'Hello'];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Bytes', async () => {
+        // Description:
+        //   Two dynamic arrays with the same values.
+        //   In the optimized calldata, only one set of elements should be included.
+        //   Both arrays should point to this set.
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateBytes);
+        const value = '0x01020304050607080910111213141516171819202122232425262728293031323334353637383940';
+        const args = [value, value];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Tuples', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
+        const tuple1 = ['Hello, World!', new BigNumber(424234)];
+        const tuple2 = tuple1;
+        const args = [tuple1, tuple2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Fields Across Two Tuples', async () => {
+        // Description:
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
+        const tuple1 = ['Hello, World!', new BigNumber(1)];
+        const tuple2 = [tuple1[0], new BigNumber(2)];
+        const args = [tuple1, tuple2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Arrays, Nested in Separate Tuples', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateArraysNestedInTuples);
+        const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200)];
+        const tuple1 = [array];
+        const tuple2 = [array, 'extra argument to prevent exactly matching the tuples'];
+        const args = [tuple1, tuple2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Tuples, Nested in Separate Tuples', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuplesNestedInTuples);
+        const nestedTuple = ['Hello, World!'];
+        const tuple1 = [nestedTuple];
+        const tuple2 = [nestedTuple, 'extra argument to prevent exactly matching the tuples'];
+        const args = [tuple1, tuple2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Two-Dimensional Arrays', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
+        const twoDimArray1 = [['Hello', 'World'], ['Foo', 'Bar', 'Zaa']];
+        const twoDimArray2 = twoDimArray1;
+        const args = [twoDimArray1, twoDimArray2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: false });
+        const expectedOptimizedCalldata =
+            '0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Duplicate Array, Nested within Separate Two-Dimensional Arrays', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
+        const twoDimArray1 = [['Hello', 'World'], ['Foo']];
+        const twoDimArray2 = [['Hello', 'World'], ['Bar']];
+        const args = [twoDimArray1, twoDimArray2];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Array Elements Duplicated as Tuple Fields', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsTupleFields);
+        const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
+        const tuple = [[array[0]], [array[1]], [array[2]], [array[3]]];
+        const args = [array, tuple];
+        // Validata calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+    it('Array Elements Duplicated as Separate Parameter', async () => {
+        // Generate calldata
+        const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsSeparateParameter);
+        const array = ['Hello', 'Hello', 'Hello', 'World'];
+        const str = 'Hello';
+        const args = [array, str];
+        // Validate calldata
+        const optimizedCalldata = method.encode(args, { optimize: true });
+        const expectedOptimizedCalldata =
+            '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+        expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+        // Validate decoding
+        const decodedArgs = method.decode(optimizedCalldata);
+        const decodedArgsJson = JSON.stringify(decodedArgs);
+        const argsJson = JSON.stringify(args);
+        expect(decodedArgsJson).to.be.equal(argsJson);
+    });
+});
diff --git a/packages/utils/test/abi_encoder/return_values_test.ts b/packages/utils/test/abi_encoder/return_values_test.ts
new file mode 100644
index 000000000..850cb1746
--- /dev/null
+++ b/packages/utils/test/abi_encoder/return_values_test.ts
@@ -0,0 +1,78 @@
+import * as chai from 'chai';
+import 'mocha';
+
+import { AbiEncoder } from '../../src/';
+import { chaiSetup } from '../utils/chai_setup';
+
+import * as ReturnValueAbis from './abi_samples/return_value_abis';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('ABI Encoder: Return Value Encoding/Decoding', () => {
+    it('No Return Value', async () => {
+        // Decode return value
+        const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
+        const returnValue = '0x';
+        const decodedReturnValue = method.decodeReturnValues(returnValue);
+        const expectedDecodedReturnValue: any[] = [];
+        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+        const expectedDecodedReturnValueJson = JSON.stringify(expectedDecodedReturnValue);
+        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+    });
+    it('Single static return value', async () => {
+        // Generate Return Value
+        const method = new AbiEncoder.Method(ReturnValueAbis.singleStaticReturnValue);
+        const returnValue = ['0x01020304'];
+        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+        // Validate decoded return value
+        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+    });
+    it('Multiple static return values', async () => {
+        // Generate Return Value
+        const method = new AbiEncoder.Method(ReturnValueAbis.multipleStaticReturnValues);
+        const returnValue = ['0x01020304', '0x05060708'];
+        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+        // Validate decoded return value
+        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+    });
+    it('Single dynamic return value', async () => {
+        // Generate Return Value
+        const method = new AbiEncoder.Method(ReturnValueAbis.singleDynamicReturnValue);
+        const returnValue = ['0x01020304'];
+        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+        // Validate decoded return value
+        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+    });
+    it('Multiple dynamic return values', async () => {
+        // Generate Return Value
+        const method = new AbiEncoder.Method(ReturnValueAbis.multipleDynamicReturnValues);
+        const returnValue = ['0x01020304', '0x05060708'];
+        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+        // Validate decoded return value
+        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+    });
+    it('Mixed static/dynamic return values', async () => {
+        // Generate Return Value
+        const method = new AbiEncoder.Method(ReturnValueAbis.mixedStaticAndDynamicReturnValues);
+        const returnValue = ['0x01020304', '0x05060708'];
+        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+        // Validate decoded return value
+        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
+        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
+        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+    });
+});
diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts
deleted file mode 100644
index 35eb8d0a9..000000000
--- a/packages/utils/test/abi_encoder_test.ts
+++ /dev/null
@@ -1,1852 +0,0 @@
-import * as chai from 'chai';
-import * as ethUtil from 'ethereumjs-util';
-import 'mocha';
-
-import { AbiEncoder, BigNumber } from '../src/';
-
-import * as AbiSamples from './abi_samples';
-import * as OptimizedAbis from './optimizer_abis';
-import * as ReturnValueAbis from './return_value_abis';
-import { chaiSetup } from './utils/chai_setup';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe.only('ABI Encoder', () => {
-    describe('Decode Return Values', () => {
-        it('No Return Value', async () => {
-            // Decode return value
-            const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
-            const returnValue = '0x';
-            const decodedReturnValue = method.decodeReturnValues(returnValue);
-            const expectedDecodedReturnValue: any[] = [];
-            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-            const expectedDecodedReturnValueJson = JSON.stringify(expectedDecodedReturnValue);
-            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
-        });
-        it('Single static return value', async () => {
-            // Generate Return Value
-            const method = new AbiEncoder.Method(ReturnValueAbis.singleStaticReturnValue);
-            const returnValue = ['0x01020304'];
-            const encodedReturnValue = method.encodeReturnValues(returnValue);
-            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
-            // Validate decoded return value
-            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
-        });
-        it('Multiple static return values', async () => {
-            // Generate Return Value
-            const method = new AbiEncoder.Method(ReturnValueAbis.multipleStaticReturnValues);
-            const returnValue = ['0x01020304', '0x05060708'];
-            const encodedReturnValue = method.encodeReturnValues(returnValue);
-            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
-            // Validate decoded return value
-            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
-        });
-        it('Single dynamic return value', async () => {
-            // Generate Return Value
-            const method = new AbiEncoder.Method(ReturnValueAbis.singleDynamicReturnValue);
-            const returnValue = ['0x01020304'];
-            const encodedReturnValue = method.encodeReturnValues(returnValue);
-            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
-            // Validate decoded return value
-            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
-        });
-        it('Multiple dynamic return values', async () => {
-            // Generate Return Value
-            const method = new AbiEncoder.Method(ReturnValueAbis.multipleDynamicReturnValues);
-            const returnValue = ['0x01020304', '0x05060708'];
-            const encodedReturnValue = method.encodeReturnValues(returnValue);
-            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
-            // Validate decoded return value
-            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
-        });
-        it('Mixed static/dynamic return values', async () => {
-            // Generate Return Value
-            const method = new AbiEncoder.Method(ReturnValueAbis.mixedStaticAndDynamicReturnValues);
-            const returnValue = ['0x01020304', '0x05060708'];
-            const encodedReturnValue = method.encodeReturnValues(returnValue);
-            const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
-            // Validate decoded return value
-            const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-            const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-            expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
-        });
-    });
-
-    describe('Optimizer', () => {
-        it('Duplicate Dynamic Arrays with Static Elements', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
-            const array1 = [new BigNumber(100), new BigNumber(150)];
-            const array2 = array1;
-            const args = [array1, array2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Dynamic Arrays with Dynamic Elements', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements);
-            const array1 = ['Hello', 'World'];
-            const array2 = array1;
-            const args = [array1, array2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Static Arrays with Static Elements (should not optimize)', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithStaticElements);
-            const array1 = [new BigNumber(100), new BigNumber(150)];
-            const array2 = array1;
-            const args = [array1, array2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x7f8130430000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            const unoptimizedCalldata = method.encode(args);
-            expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Static Arrays with Dynamic Elements', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements);
-            const array1 = ['Hello', 'World'];
-            const array2 = array1;
-            const args = [array1, array2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Array Elements (should optimize)', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateArrayElements);
-            const strings = ['Hello', 'World', 'Hello', 'World'];
-            const args = [strings];
-            // Validate calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Tuple Fields', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTupleFields);
-            const tuple = ['Hello', 'Hello'];
-            const args = [tuple];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Strings', async () => {
-            // Description:
-            //   Two dynamic arrays with the same values.
-            //   In the optimized calldata, only one set of elements should be included.
-            //   Both arrays should point to this set.
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateStrings);
-            const args = ['Hello', 'Hello'];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Bytes', async () => {
-            // Description:
-            //   Two dynamic arrays with the same values.
-            //   In the optimized calldata, only one set of elements should be included.
-            //   Both arrays should point to this set.
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateBytes);
-            const value = '0x01020304050607080910111213141516171819202122232425262728293031323334353637383940';
-            const args = [value, value];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Tuples', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
-            const tuple1 = ['Hello, World!', new BigNumber(424234)];
-            const tuple2 = tuple1;
-            const args = [tuple1, tuple2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Fields Across Two Tuples', async () => {
-            // Description:
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples);
-            const tuple1 = ['Hello, World!', new BigNumber(1)];
-            const tuple2 = [tuple1[0], new BigNumber(2)];
-            const args = [tuple1, tuple2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Arrays, Nested in Separate Tuples', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateArraysNestedInTuples);
-            const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200)];
-            const tuple1 = [array];
-            const tuple2 = [array, 'extra argument to prevent exactly matching the tuples'];
-            const args = [tuple1, tuple2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Tuples, Nested in Separate Tuples', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuplesNestedInTuples);
-            const nestedTuple = ['Hello, World!'];
-            const tuple1 = [nestedTuple];
-            const tuple2 = [nestedTuple, 'extra argument to prevent exactly matching the tuples'];
-            const args = [tuple1, tuple2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Two-Dimensional Arrays', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
-            const twoDimArray1 = [['Hello', 'World'], ['Foo', 'Bar', 'Zaa']];
-            const twoDimArray2 = twoDimArray1;
-            const args = [twoDimArray1, twoDimArray2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: false });
-            const expectedOptimizedCalldata =
-                '0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Duplicate Array, Nested within Separate Two-Dimensional Arrays', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays);
-            const twoDimArray1 = [['Hello', 'World'], ['Foo']];
-            const twoDimArray2 = [['Hello', 'World'], ['Bar']];
-            const args = [twoDimArray1, twoDimArray2];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Array Elements Duplicated as Tuple Fields', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsTupleFields);
-            const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)];
-            const tuple = [[array[0]], [array[1]], [array[2]], [array[3]]];
-            const args = [array, tuple];
-            // Validata calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-        it('Array Elements Duplicated as Separate Parameter', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsSeparateParameter);
-            const array = ['Hello', 'Hello', 'Hello', 'World'];
-            const str = 'Hello';
-            const args = [array, str];
-            // Validate calldata
-            const optimizedCalldata = method.encode(args, { optimize: true });
-            const expectedOptimizedCalldata =
-                '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
-            expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
-            // Validate decoding
-            const decodedArgs = method.decode(optimizedCalldata);
-            const decodedArgsJson = JSON.stringify(decodedArgs);
-            const argsJson = JSON.stringify(args);
-            expect(decodedArgsJson).to.be.equal(argsJson);
-        });
-    });
-
-    describe('Method ABIs', () => {
-        it('Types with default widths', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
-            const args = [
-                new BigNumber(1),
-                new BigNumber(-1),
-                '0x56',
-                [new BigNumber(1)],
-                [new BigNumber(-1)],
-                ['0x56'],
-            ];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Array of Static Tuples (Array has defined length)', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi);
-            let value = 0;
-            const arrayOfTuples = [];
-            const arrayOfTuplesLength = 8;
-            for (let i = 0; i < arrayOfTuplesLength; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Array of Static Tuples (Array has dynamic length)', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi);
-            let value = 0;
-            const arrayOfTuples = [];
-            const arrayOfTuplesLength = 8;
-            for (let i = 0; i < arrayOfTuplesLength; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Array of Dynamic Tuples (Array has defined length)', async () => {
-            // Generate Calldata
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi);
-            let value = 0;
-            const arrayOfTuples = [];
-            const arrayOfTuplesLength = 8;
-            for (let i = 0; i < arrayOfTuplesLength; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi);
-            let value = 0;
-            const arrayOfTuples = [];
-            const arrayOfTuplesLength = 8;
-            for (let i = 0; i < arrayOfTuplesLength; ++i) {
-                arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
-            }
-            const args = [arrayOfTuples];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Multidimensional Arrays / Static Members', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi);
-            // Eight 3-dimensional arrays of uint8[2][2][2]
-            let value = 0;
-            const args = [];
-            const argsLength = 8;
-            for (let i = 0; i < argsLength; ++i) {
-                args.push([
-                    [
-                        [new BigNumber(++value), new BigNumber(++value)],
-                        [new BigNumber(++value), new BigNumber(++value)],
-                    ],
-                    [
-                        [new BigNumber(++value), new BigNumber(++value)],
-                        [new BigNumber(++value), new BigNumber(++value)],
-                    ],
-                ]);
-            }
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038';
-            expect(calldata).to.be.equal(expectedCalldata);
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Multidimensional Arrays / Dynamic Members', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi);
-            // Eight 3-dimensional arrays of string[2][2][2]
-            let value = 0;
-            const args = [];
-            const argsLength = 4;
-            for (let i = 0; i < argsLength; ++i) {
-                args.push([
-                    [
-                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                    ],
-                    [
-                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                        [new BigNumber(++value).toString(), new BigNumber(++value).toString()],
-                    ],
-                ]);
-            }
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Fixed Length Array / Dynamic Members', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
-            const args = [['Brave', 'New', 'World']];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Fixed Length Array / Dynamic Members', async () => {
-            // Generaet calldata
-            const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
-            const args = [['Brave', 'New', 'World']];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Unfixed Length Array / Dynamic Members ABI', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
-            const args = [['Brave', 'New', 'World']];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Unfixed Length Array / Static Members ABI', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Fixed Length Array / Static Members ABI', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
-            const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Array ABI', async () => {
-            // Generate calldata
-            const method = new AbiEncoder.Method(AbiSamples.stringAbi);
-            const args = [['five', 'six', 'seven']];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Static Tuple', async () => {
-            // Generate calldata
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
-            const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Dynamic Tuple (Array input)', async () => {
-            // Generate calldata
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const args = [[new BigNumber(5), 'five']];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Dynamic Tuple (Object input)', async () => {
-            // Generate Calldata
-            // This is dynamic because it has dynamic members
-            const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
-            const args = [[new BigNumber(5), 'five']];
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Large, Flat ABI', async () => {
-            // Construct calldata
-            const method = new AbiEncoder.Method(AbiSamples.largeFlatAbi);
-            const args = [
-                new BigNumber(256745454),
-                new BigNumber(-256745454),
-                new BigNumber(434244),
-                '0x43',
-                '0x0001020304050607080911121314151617181920212223242526272829303132',
-                '0x0001020304050607080911121314151617181920212223242526272829303132080911121314151617181920212223242526272829303132',
-                'Little peter piper piped a piping pepper pot',
-                '0xe41d2489571d322189246dafa5ebde1f4699f498',
-                true,
-            ];
-            // Validate calldata
-            const calldata = method.encode(args);
-            const expectedCalldata =
-                '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata);
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-        it('Large, Nested ABI', async () => {
-            // Construct Calldata
-            const method = new AbiEncoder.Method(AbiSamples.largeNestedAbi);
-            const someStaticArray = [new BigNumber(127), new BigNumber(14), new BigNumber(54)];
-            const someStaticArrayWithDynamicMembers = [
-                'the little piping piper piped a piping pipper papper',
-                'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-            ];
-            const someDynamicArrayWithDynamicMembers = [
-                '0x38745637834987324827439287423897238947239847',
-                '0x7283472398237423984723984729847248927498748974284728947239487498749847874329423743492347329847239842374892374892374892347238947289478947489374289472894738942749823743298742389472389473289472389437249823749823742893472398',
-                '0x283473298473248923749238742398742398472894729843278942374982374892374892743982',
-            ];
-            const some2DArray = [
-                [
-                    'some string',
-                    'some another string',
-                    'there are just too many stringsup in',
-                    'here',
-                    'yall ghonna make me lose my mind',
-                ],
-                [
-                    'the little piping piper piped a piping pipper papper',
-                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-                ],
-                [],
-            ];
-            const someTuple = {
-                someUint32: new BigNumber(4037824789),
-                someStr:
-                    'the kid knows how to write poems, what can I say -- I guess theres a lot I could say to try to fill this line with a lot of text.',
-            };
-            const someTupleWithDynamicTypes = {
-                someUint: new BigNumber(4024789),
-                someStr: 'akdhjasjkdhasjkldshdjahdkjsahdajksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjk',
-                someBytes: '0x29384723894723843743289742389472398473289472348927489274894738427428947389facdea',
-                someAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
-            };
-            const someTupleWithDynamicTypes2 = {
-                someUint: new BigNumber(9024789),
-                someStr: 'ksdhsajkdhsajkdhadjkashdjksadhajkdhsajkdhsadjkakdhjasjkdhasjkldshdjahdkjsahdaj',
-                someBytes: '0x29384723894398473289472348927489272384374328974238947274894738427428947389facde1',
-                someAddress: '0x746dafa5ebde1f4699f4981d3221892e41d24895',
-            };
-            const someTupleWithDynamicTypes3 = {
-                someUint: new BigNumber(1024789),
-                someStr: 'sdhsajkdhsajkdhadjkashdjakdhjasjkdhasjkldshdjahdkjsahdajkksadhajkdhsajkdhsadjk',
-                someBytes: '0x38947238437432829384729742389472398473289472348927489274894738427428947389facdef',
-                someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa',
-            };
-            const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3];
-            const args = {
-                someStaticArray,
-                someStaticArrayWithDynamicMembers,
-                someDynamicArrayWithDynamicMembers,
-                some2DArray,
-                someTuple,
-                someTupleWithDynamicTypes,
-                someArrayOfTuplesWithDynamicTypes,
-            };
-            const calldata = method.encode(args);
-            // Validate calldata
-            const expectedCalldata =
-                '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
-            expect(calldata).to.be.equal(expectedCalldata);
-            // Validate decoding
-            const expectedDecodedValueJson = JSON.stringify(args);
-            const decodedValue = method.decode(calldata, { structsAsObjects: true });
-            const decodedValueJson = JSON.stringify(decodedValue);
-            expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
-        });
-    });
-
-    describe('Array', () => {
-        it('Fixed size; Static elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'int[2]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = [new BigNumber(5), new BigNumber(6)];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Dynamic size; Static elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'int[]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = [new BigNumber(5), new BigNumber(6)];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Fixed size; Dynamic elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'string[2]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = ['Hello', 'world'];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Dynamic size; Dynamic elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'string[]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = ['Hello', 'world'];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Dynamic Size; Multidimensional; Dynamic Elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'bytes[][]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
-            const array2 = ['0x10111213', '0x14151617'];
-            const array3 = ['0x18192021'];
-            const args = [array1, array2, array3];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000041011121300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414151617000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Dynamic Size; Multidimensional; Static Elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'bytes4[][]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
-            const array2 = ['0x10111213', '0x14151617'];
-            const array3 = ['0x18192021'];
-            const args = [array1, array2, array3];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000301020304000000000000000000000000000000000000000000000000000000000506070800000000000000000000000000000000000000000000000000000000091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021011121300000000000000000000000000000000000000000000000000000000141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011819202100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Static Size; Multidimensional; Static Elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'bytes4[3][2]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
-            const array2 = ['0x10111213', '0x14151617', '0x18192021'];
-            const args = [array1, array2];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x010203040000000000000000000000000000000000000000000000000000000005060708000000000000000000000000000000000000000000000000000000000910111200000000000000000000000000000000000000000000000000000000101112130000000000000000000000000000000000000000000000000000000014151617000000000000000000000000000000000000000000000000000000001819202100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Static Size; Multidimensional; Dynamic Elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'bytes[3][2]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const array1 = ['0x01020304', '0x05060708', '0x09101112'];
-            const array2 = ['0x10111213', '0x14151617', '0x18192021'];
-            const args = [array1, array2];
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000401020304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040910111200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000410111213000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Static size; Too Few Elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'string[3]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = ['Hello', 'world'];
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw('Expected array of 3 elements, but got array of length 2');
-        });
-        it('Static size; Too Many Elements', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'string[1]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = ['Hello', 'world'];
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw('Expected array of 1 elements, but got array of length 2');
-        });
-        it('Element Type Mismatch', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'testArray', type: 'uint[]' };
-            const dataType = new AbiEncoder.Array(testDataItem);
-            // Construct args to be encoded
-            const args = [new BigNumber(1), 'Bad Argument'];
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-    });
-
-    describe('Tuple', () => {
-        it('Static elements only', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = { field_1: new BigNumber(-5), field_2: true };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Dynamic elements only', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field_1', type: 'string' }, { name: 'field_2', type: 'bytes' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = { field_1: 'Hello, World!', field_2: '0xabcdef0123456789' };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Nested Static Array', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field', type: 'uint[2]' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = { field: [new BigNumber(1), new BigNumber(2)] };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Nested Dynamic Array', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field', type: 'uint[]' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = { field: [new BigNumber(1), new BigNumber(2)] };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Nested Static Multidimensional Array', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field', type: 'bytes4[2][2]' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const array1 = ['0x01020304', '0x05060708'];
-            const array2 = ['0x09101112', '0x13141516'];
-            const args = { field: [array1, array2] };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Nested Dynamic Multidimensional Array', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field', type: 'bytes[2][2]' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const array1 = ['0x01020304', '0x05060708'];
-            const array2 = ['0x09101112', '0x13141516'];
-            const args = { field: [array1, array2] };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Static and dynamic elements mixed', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [
-                    { name: 'field_1', type: 'int32' },
-                    { name: 'field_2', type: 'string' },
-                    { name: 'field_3', type: 'bool' },
-                    { name: 'field_4', type: 'bytes' },
-                ],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = {
-                field_1: new BigNumber(-5),
-                field_2: 'Hello, World!',
-                field_3: true,
-                field_4: '0xabcdef0123456789',
-            };
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
-            const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Missing Key', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = { field_1: new BigNumber(-5) };
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw('Could not assign tuple to object: missing keys field_2');
-        });
-        it('Bad Key', async () => {
-            // Create DataType object
-            const testDataItem = {
-                name: 'Tuple',
-                type: 'tuple',
-                components: [{ name: 'field_1', type: 'int32' }, { name: 'field_2', type: 'bool' }],
-            };
-            const dataType = new AbiEncoder.Tuple(testDataItem);
-            // Construct args to be encoded
-            const args = { unknown_field: new BigNumber(-5) };
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw("Could not assign tuple to object: unrecognized key 'unknown_field' in object Tuple");
-        });
-    });
-
-    describe('Address', () => {
-        it('Valid Address', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Address', type: 'address' };
-            const dataType = new AbiEncoder.Address(testDataItem);
-            // Construct args to be encoded
-            const args = '0xe41d2489571d322189246dafa5ebde1f4699f498';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Invalid Address - input is not valid hex', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Address', type: 'address' };
-            const dataType = new AbiEncoder.Address(testDataItem);
-            // Construct args to be encoded
-            const args = 'e4';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
-        });
-        it('Invalid Address - input is not 20 bytes', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Address', type: 'address' };
-            const dataType = new AbiEncoder.Address(testDataItem);
-            // Construct args to be encoded
-            const args = '0xe4';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
-        });
-    });
-
-    describe('Bool', () => {
-        it('True', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Boolean', type: 'bool' };
-            const dataType = new AbiEncoder.Bool(testDataItem);
-            // Construct args to be encoded
-            const args = true;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('False', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Boolean', type: 'bool' };
-            const dataType = new AbiEncoder.Bool(testDataItem);
-            // Construct args to be encoded
-            const args = false;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-    });
-
-    describe('Integer', () => {
-        /* tslint:disable custom-no-magic-numbers */
-        const max256BitInteger = new BigNumber(2).pow(255).minus(1);
-        const min256BitInteger = new BigNumber(2).pow(255).times(-1);
-        const max32BitInteger = new BigNumber(2).pow(31).minus(1);
-        const min32BitInteger = new BigNumber(2).pow(31).times(-1);
-        /* tslint:enable custom-no-magic-numbers */
-
-        it('Int256 - Positive Base Case', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (256)', type: 'int' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = new BigNumber(1);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int256 - Negative Base Case', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (256)', type: 'int' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = new BigNumber(-1);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int256 - Positive Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (256)', type: 'int' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = max256BitInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int256 - Negative Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (256)', type: 'int' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = min256BitInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = `0x8000000000000000000000000000000000000000000000000000000000000000`;
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int256 - Value too large', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (256)', type: 'int' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = max256BitInteger.plus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-        it('Int256 - Value too small', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (256)', type: 'int' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = min256BitInteger.minus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-        it('Int32 - Positive Base Case', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (32)', type: 'int32' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = new BigNumber(1);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int32 - Negative Base Case', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (32)', type: 'int32' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = new BigNumber(-1);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int32 - Positive Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (32)', type: 'int32' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = max32BitInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000007fffffff';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int32 - Negative Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (32)', type: 'int32' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = min32BitInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000`;
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Int32 - Value too large', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (32)', type: 'int32' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = max32BitInteger.plus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-        it('Int32 - Value too small', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Integer (32)', type: 'int32' };
-            const dataType = new AbiEncoder.Int(testDataItem);
-            // Construct args to be encoded
-            const args = min32BitInteger.minus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-    });
-
-    describe('Unsigned Integer', () => {
-        /* tslint:disable custom-no-magic-numbers */
-        const max256BitUnsignedInteger = new BigNumber(2).pow(256).minus(1);
-        const min256BitUnsignedInteger = new BigNumber(0);
-        const max32BitUnsignedInteger = new BigNumber(2).pow(32).minus(1);
-        const min32BitUnsignedInteger = new BigNumber(0);
-        /* tslint:enable custom-no-magic-numbers */
-
-        it('UInt256 - Positive Base Case', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = new BigNumber(1);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('UInt256 - Positive Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = max256BitUnsignedInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('UInt256 - Zero Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = min256BitUnsignedInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('UInt256 - Value too large', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = max256BitUnsignedInteger.plus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-        it('UInt256 - Value too small', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (256)', type: 'uint' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = min256BitUnsignedInteger.minus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-        it('UInt32 - Positive Base Case', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = new BigNumber(1);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('UInt32 - Positive Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = max32BitUnsignedInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000ffffffff';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('UInt32 - Zero Value', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = min32BitUnsignedInteger;
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('UInt32 - Value too large', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = max32BitUnsignedInteger.plus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-        it('UInt32 - Value too small', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Unsigned Integer (32)', type: 'uint32' };
-            const dataType = new AbiEncoder.UInt(testDataItem);
-            // Construct args to be encoded
-            const args = min32BitUnsignedInteger.minus(1);
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw();
-        });
-    });
-
-    describe('Static Bytes', () => {
-        it('Single Byte (byte)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Byte', type: 'byte' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x05';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Single Byte (bytes1)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes1', type: 'bytes1' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x05';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('4 Bytes (bytes4)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x00010203';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0001020300000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('4 Bytes (bytes4); Encoder must pad input', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = '0x1a18';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x1a18000000000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const paddedArgs = '0x1a180000';
-            const paddedArgsAsJson = JSON.stringify(paddedArgs);
-            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
-        });
-        it('32 Bytes (bytes32)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x0001020304050607080911121314151617181920212223242526272829303132';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x0001020304050607080911121314151617181920212223242526272829303132';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('32 Bytes (bytes32); Encoder must pad input', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = '0x1a18bf61';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const paddedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-            const paddedArgsAsJson = JSON.stringify(paddedArgs);
-            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
-        });
-        it('Should throw when pass in too many bytes (bytes4)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes4', type: 'bytes4' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x0102030405';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw(
-                'Tried to assign 0x0102030405 (5 bytes), which exceeds max bytes that can be stored in a bytes4',
-            );
-        });
-        it('Should throw when pass in too many bytes (bytes32)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x010203040506070809101112131415161718192021222324252627282930313233';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw(
-                'Tried to assign 0x010203040506070809101112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32',
-            );
-        });
-        it('Should throw when pass in bad hex (no 0x prefix)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0102030405060708091011121314151617181920212223242526272829303132';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
-        });
-        it('Should throw when pass in bad hex (include a half-byte)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes32', type: 'bytes32' };
-            const dataType = new AbiEncoder.StaticBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x010';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
-        });
-    });
-
-    describe('Dynamic Bytes', () => {
-        it('Fits into one EVM word', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = '0x1a18bf61';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Spans multiple EVM words', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const bytesLength = 40;
-            const args = '0x' + '61'.repeat(bytesLength);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Input as Buffer', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Dynamic Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = '0x1a18bf61';
-            const argsAsBuffer = ethUtil.toBuffer(args);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(argsAsBuffer);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Should throw when pass in bad hex (no 0x prefix)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '01';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
-        });
-        it('Should throw when pass in bad hex (include a half-byte)', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'Static Bytes', type: 'bytes' };
-            const dataType = new AbiEncoder.DynamicBytes(testDataItem);
-            // Construct args to be encoded
-            const args = '0x010';
-            // Encode Args and validate result
-            expect(() => {
-                dataType.encode(args);
-            }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
-        });
-    });
-
-    describe('String', () => {
-        it('Fits into one EVM word', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'String', type: 'string' };
-            const dataType = new AbiEncoder.String(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const args = 'five';
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('Spans multiple EVM words', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'String', type: 'string' };
-            const dataType = new AbiEncoder.String(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const bytesLength = 40;
-            const args = 'a'.repeat(bytesLength);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-        it('String that begins with 0x prefix', async () => {
-            // Create DataType object
-            const testDataItem = { name: 'String', type: 'string' };
-            const dataType = new AbiEncoder.String(testDataItem);
-            // Construct args to be encoded
-            // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
-            const strLength = 40;
-            const args = '0x' + 'a'.repeat(strLength);
-            // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
-            const expectedEncodedArgs =
-                '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
-            expect(encodedArgs).to.be.equal(expectedEncodedArgs);
-            // Decode Encoded Args and validate result
-            const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
-        });
-    });
-});
diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts
deleted file mode 100644
index fc552c127..000000000
--- a/packages/utils/test/abi_samples.ts
+++ /dev/null
@@ -1,780 +0,0 @@
-/* tslint:disable max-file-line-count */
-import { MethodAbi } from 'ethereum-types';
-
-export const simpleAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'greg',
-            type: 'uint256',
-        },
-        {
-            name: 'gregStr',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const stringAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'greg',
-            type: 'string[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const GAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'a',
-                    type: 'uint256',
-                },
-                {
-                    name: 'b',
-                    type: 'string',
-                },
-                {
-                    name: 'e',
-                    type: 'bytes',
-                },
-                {
-                    name: 'f',
-                    type: 'address',
-                },
-            ],
-
-            name: 'f',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const typesWithDefaultWidthsAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someUint',
-            type: 'uint',
-        },
-        {
-            name: 'someInt',
-            type: 'int',
-        },
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someUint',
-            type: 'uint[]',
-        },
-        {
-            name: 'someInt',
-            type: 'int[]',
-        },
-        {
-            name: 'someByte',
-            type: 'byte[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const multiDimensionalArraysStaticTypeAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'a',
-            type: 'uint8[][][]',
-        },
-        {
-            name: 'b',
-            type: 'uint8[][][2]',
-        },
-        {
-            name: 'c',
-            type: 'uint8[][2][]',
-        },
-        {
-            name: 'd',
-            type: 'uint8[2][][]',
-        },
-        {
-            name: 'e',
-            type: 'uint8[][2][2]',
-        },
-        {
-            name: 'f',
-            type: 'uint8[2][2][]',
-        },
-        {
-            name: 'g',
-            type: 'uint8[2][][2]',
-        },
-        {
-            name: 'h',
-            type: 'uint8[2][2][2]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const multiDimensionalArraysDynamicTypeAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'a',
-            type: 'string[][][]',
-        },
-        {
-            name: 'b',
-            type: 'string[][][2]',
-        },
-        {
-            name: 'c',
-            type: 'string[][2][]',
-        },
-        {
-            name: 'h',
-            type: 'string[2][2][2]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const dynamicTupleAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayOfStaticTuplesWithDefinedLengthAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint2',
-                    type: 'uint256',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[8]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayOfStaticTuplesWithDynamicLengthAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint2',
-                    type: 'uint256',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayOfDynamicTuplesWithDefinedLengthAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[8]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayOfDynamicTuplesWithUndefinedLengthAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayOfDynamicTuplesAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const multidimensionalArrayOfDynamicTuplesAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someString',
-                    type: 'string',
-                },
-            ],
-            name: 'order',
-            type: 'tuple[][2][]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const staticTupleAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'someUint1',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint2',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someUint3',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someBool',
-                    type: 'bool',
-                },
-            ],
-            name: 'order',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const staticArrayAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[3]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const staticArrayDynamicMembersAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'string[3]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const dynamicArrayDynamicMembersAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'string[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const dynamicArrayStaticMembersAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const largeFlatAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someUInt256',
-            type: 'uint256',
-        },
-        {
-            name: 'someInt256',
-            type: 'int256',
-        },
-        {
-            name: 'someInt32',
-            type: 'int32',
-        },
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someBytes32',
-            type: 'bytes32',
-        },
-        {
-            name: 'someBytes',
-            type: 'bytes',
-        },
-        {
-            name: 'someString',
-            type: 'string',
-        },
-        {
-            name: 'someAddress',
-            type: 'address',
-        },
-        {
-            name: 'someBool',
-            type: 'bool',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const largeNestedAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someStaticArray',
-            type: 'uint8[3]',
-        },
-        {
-            name: 'someStaticArrayWithDynamicMembers',
-            type: 'string[2]',
-        },
-        {
-            name: 'someDynamicArrayWithDynamicMembers',
-            type: 'bytes[]',
-        },
-        {
-            name: 'some2DArray',
-            type: 'string[][]',
-        },
-        {
-            name: 'someTuple',
-            type: 'tuple',
-            components: [
-                {
-                    name: 'someUint32',
-                    type: 'uint32',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-            ],
-        },
-        {
-            name: 'someTupleWithDynamicTypes',
-            type: 'tuple',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                /*{
-                    name: 'someStrArray',
-                    type: 'string[]',
-                },*/
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        },
-        {
-            name: 'someArrayOfTuplesWithDynamicTypes',
-            type: 'tuple[]',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                /*{
-                    name: 'someStrArray',
-                    type: 'string[]',
-                },*/
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const nestedTuples: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'firstTuple',
-            type: 'tuple[1]',
-            components: [
-                {
-                    name: 'someUint32',
-                    type: 'uint32',
-                },
-                {
-                    name: 'nestedTuple',
-                    type: 'tuple',
-                    components: [
-                        {
-                            name: 'someUint',
-                            type: 'uint256',
-                        },
-                        {
-                            name: 'someAddress',
-                            type: 'address',
-                        },
-                    ],
-                },
-            ],
-        },
-        {
-            name: 'secondTuple',
-            type: 'tuple[]',
-            components: [
-                {
-                    name: 'someUint',
-                    type: 'uint256',
-                },
-                {
-                    name: 'someStr',
-                    type: 'string',
-                },
-                {
-                    name: 'nestedTuple',
-                    type: 'tuple',
-                    components: [
-                        {
-                            name: 'someUint32',
-                            type: 'uint32',
-                        },
-                        {
-                            name: 'secondNestedTuple',
-                            type: 'tuple',
-                            components: [
-                                {
-                                    name: 'someUint',
-                                    type: 'uint256',
-                                },
-                                {
-                                    name: 'someStr',
-                                    type: 'string',
-                                },
-                                {
-                                    name: 'someBytes',
-                                    type: 'bytes',
-                                },
-                                {
-                                    name: 'someAddress',
-                                    type: 'address',
-                                },
-                            ],
-                        },
-                    ],
-                },
-                {
-                    name: 'someBytes',
-                    type: 'bytes',
-                },
-                {
-                    name: 'someAddress',
-                    type: 'address',
-                },
-            ],
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const simpleAbi2: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'someByte',
-            type: 'byte',
-        },
-        {
-            name: 'someBytes32',
-            type: 'bytes32',
-        },
-        {
-            name: 'someBytes',
-            type: 'bytes',
-        },
-        {
-            name: 'someString',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const fillOrderAbi: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            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: 'order',
-            type: 'tuple',
-        },
-        {
-            name: 'takerAssetFillAmount',
-            type: 'uint256',
-        },
-        {
-            name: 'salt',
-            type: 'uint256',
-        },
-        {
-            name: 'orderSignature',
-            type: 'bytes',
-        },
-        {
-            name: 'takerSignature',
-            type: 'bytes',
-        },
-    ],
-    name: 'fillOrder',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
diff --git a/packages/utils/test/optimizer_abis.ts b/packages/utils/test/optimizer_abis.ts
deleted file mode 100644
index 7cfd7a118..000000000
--- a/packages/utils/test/optimizer_abis.ts
+++ /dev/null
@@ -1,340 +0,0 @@
-/* tslint:disable max-file-line-count */
-import { MethodAbi } from 'ethereum-types';
-
-export const duplicateDynamicArraysWithStaticElements: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array1',
-            type: 'uint[]',
-        },
-        {
-            name: 'array2',
-            type: 'uint[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateDynamicArraysWithDynamicElements: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array1',
-            type: 'string[]',
-        },
-        {
-            name: 'array2',
-            type: 'string[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateStaticArraysWithStaticElements: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array1',
-            type: 'uint[2]',
-        },
-        {
-            name: 'array2',
-            type: 'uint[2]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateStaticArraysWithDynamicElements: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array1',
-            type: 'string[2]',
-        },
-        {
-            name: 'array2',
-            type: 'string[2]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateArrayElements: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array',
-            type: 'string[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateTupleFields: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'field1',
-                    type: 'string',
-                },
-                {
-                    name: 'field2',
-                    type: 'string',
-                },
-            ],
-            name: 'Tuple',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateStrings: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'string1',
-            type: 'string',
-        },
-        {
-            name: 'string2',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateBytes: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'bytes1',
-            type: 'bytes',
-        },
-        {
-            name: 'bytes2',
-            type: 'bytes',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateTuples: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'field1',
-                    type: 'string',
-                },
-                {
-                    name: 'field2',
-                    type: 'uint',
-                },
-            ],
-            name: 'Tuple',
-            type: 'tuple',
-        },
-        {
-            components: [
-                {
-                    name: 'field1',
-                    type: 'string',
-                },
-                {
-                    name: 'field2',
-                    type: 'uint',
-                },
-            ],
-            name: 'Tuple',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateArraysNestedInTuples: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    name: 'field',
-                    type: 'uint[]',
-                },
-            ],
-            name: 'Tuple1',
-            type: 'tuple',
-        },
-        {
-            components: [
-                {
-                    name: 'field',
-                    type: 'uint[]',
-                },
-                {
-                    name: 'extraField',
-                    type: 'string',
-                },
-            ],
-            name: 'Tuple2',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateTuplesNestedInTuples: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            components: [
-                {
-                    components: [
-                        {
-                            name: 'nestedField',
-                            type: 'string',
-                        },
-                    ],
-                    name: 'field',
-                    type: 'tuple',
-                },
-            ],
-            name: 'Tuple1',
-            type: 'tuple',
-        },
-        {
-            components: [
-                {
-                    components: [
-                        {
-                            name: 'nestedField',
-                            type: 'string',
-                        },
-                    ],
-                    name: 'field',
-                    type: 'tuple',
-                },
-                {
-                    name: 'extraField',
-                    type: 'string',
-                },
-            ],
-            name: 'Tuple1',
-            type: 'tuple',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const duplicateTwoDimensionalArrays: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'array1',
-            type: 'string[][]',
-        },
-        {
-            name: 'array2',
-            type: 'string[][]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayElementsDuplicatedAsSeparateParameter: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'stringArray',
-            type: 'string[]',
-        },
-        {
-            name: 'string',
-            type: 'string',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const arrayElementsDuplicatedAsTupleFields: MethodAbi = {
-    constant: false,
-    inputs: [
-        {
-            name: 'uint8Array',
-            type: 'uint8[]',
-        },
-        {
-            components: [
-                {
-                    name: 'uint',
-                    type: 'uint',
-                },
-            ],
-            name: 'uintTuple',
-            type: 'tuple[]',
-        },
-    ],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
diff --git a/packages/utils/test/return_value_abis.ts b/packages/utils/test/return_value_abis.ts
deleted file mode 100644
index ac2124011..000000000
--- a/packages/utils/test/return_value_abis.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-/* tslint:disable max-file-line-count */
-import { MethodAbi } from 'ethereum-types';
-
-export const noReturnValues: MethodAbi = {
-    constant: false,
-    inputs: [],
-    name: 'simpleFunction',
-    outputs: [],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const singleStaticReturnValue: MethodAbi = {
-    constant: false,
-    inputs: [],
-    name: 'simpleFunction',
-    outputs: [
-        {
-            name: 'Bytes4',
-            type: 'bytes4',
-        },
-    ],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const multipleStaticReturnValues: MethodAbi = {
-    constant: false,
-    inputs: [],
-    name: 'simpleFunction',
-    outputs: [
-        {
-            name: 'val1',
-            type: 'bytes4',
-        },
-        {
-            name: 'val2',
-            type: 'bytes4',
-        },
-    ],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const singleDynamicReturnValue: MethodAbi = {
-    constant: false,
-    inputs: [],
-    name: 'simpleFunction',
-    outputs: [
-        {
-            name: 'val',
-            type: 'bytes',
-        },
-    ],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const multipleDynamicReturnValues: MethodAbi = {
-    constant: false,
-    inputs: [],
-    name: 'simpleFunction',
-    outputs: [
-        {
-            name: 'val1',
-            type: 'bytes',
-        },
-        {
-            name: 'val2',
-            type: 'bytes',
-        },
-    ],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-
-export const mixedStaticAndDynamicReturnValues: MethodAbi = {
-    constant: false,
-    inputs: [],
-    name: 'simpleFunction',
-    outputs: [
-        {
-            name: 'val1',
-            type: 'bytes4',
-        },
-        {
-            name: 'val2',
-            type: 'bytes',
-        },
-    ],
-    payable: false,
-    stateMutability: 'nonpayable',
-    type: 'function',
-};
-- 
cgit v1.2.3


From a895dacd4e20238087245c274564f694c71f7f6e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 14:18:01 -0800
Subject: moved abi encoder constants into utils dir

---
 .../src/abi_encoder/abstract_data_types/dependent_data_type.ts    | 2 +-
 .../utils/src/abi_encoder/abstract_data_types/member_data_type.ts | 2 +-
 packages/utils/src/abi_encoder/calldata/calldata.ts               | 2 +-
 .../utils/src/abi_encoder/calldata/dependent_calldata_block.ts    | 2 +-
 packages/utils/src/abi_encoder/calldata/raw_calldata.ts           | 2 +-
 packages/utils/src/abi_encoder/constants.ts                       | 8 --------
 packages/utils/src/abi_encoder/evm_data_types/address.ts          | 4 ++--
 packages/utils/src/abi_encoder/evm_data_types/array.ts            | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/bool.ts             | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts    | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/method.ts           | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/number.ts           | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts     | 4 ++--
 packages/utils/src/abi_encoder/evm_data_types/string.ts           | 2 +-
 packages/utils/src/abi_encoder/utils/constants.ts                 | 8 ++++++++
 15 files changed, 23 insertions(+), 23 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/constants.ts
 create mode 100644 packages/utils/src/abi_encoder/utils/constants.ts

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
index e9f390b22..f4992dd0f 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
@@ -3,7 +3,7 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { CalldataBlock, DependentCalldataBlock, RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 import { DecodingRules } from '../utils/rules';
 
 import { DataType } from './data_type';
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
index f44a6dd30..318564e21 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
 import { CalldataBlock, MemberCalldataBlock, RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 import { DecodingRules } from '../utils/rules';
 
 import { DataType } from './data_type';
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 1abf1b681..154a81b7f 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -1,7 +1,7 @@
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 import { Queue } from '../utils/queue';
 import { EncodingRules } from '../utils/rules';
 
diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
index 4aec5eabc..16b9a6fe6 100644
--- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
+++ b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
@@ -1,6 +1,6 @@
 import * as ethUtil from 'ethereumjs-util';
 
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 import { CalldataBlock } from './calldata_block';
 
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index b7bd35737..27a59c6a3 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -1,6 +1,6 @@
 import * as ethUtil from 'ethereumjs-util';
 
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 import { Queue } from '../utils/queue';
 
 export class RawCalldata {
diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts
deleted file mode 100644
index 3d85fbdb8..000000000
--- a/packages/utils/src/abi_encoder/constants.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export const EVM_WORD_WIDTH_IN_BYTES = 32;
-export const EVM_WORD_WIDTH_IN_BITS = 256;
-export const HEX_BASE = 16;
-export const DEC_BASE = 10;
-export const BIN_BASE = 2;
-export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
-export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
-export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 0107fdc50..aab5a0605 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export class Address extends PayloadDataType {
     public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
@@ -13,7 +13,7 @@ export class Address extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
-    Address._ADDRESS_SIZE_IN_BYTES;
+        Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
         return type === 'address';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index f334282b8..9963b6f32 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -1,7 +1,7 @@
 import { DataItem } from 'ethereum-types';
 
 import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export class Array extends MemberDataType {
     private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 4b9dd32b1..6bc299544 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -6,7 +6,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export class Bool extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index 5fca668e4..626e266c9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export class DynamicBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index ce33755f1..50d676b4a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { DataType, DataTypeFactory, MemberDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { StaticBytes } from './static_bytes';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/number.ts b/packages/utils/src/abi_encoder/evm_data_types/number.ts
index 8ff5e9a6a..86acdce07 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/number.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/number.ts
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export abstract class Number extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 4e49db609..77dde1333 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export class StaticBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
@@ -46,7 +46,7 @@ export class StaticBytes extends PayloadDataType {
         if (valueBuf.byteLength > this._width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                    valueBuf.byteLength
+                valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index c0bde8649..47ad7cb97 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../constants';
+import * as Constants from '../utils/constants';
 
 export class String extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts
new file mode 100644
index 000000000..3d85fbdb8
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -0,0 +1,8 @@
+export const EVM_WORD_WIDTH_IN_BYTES = 32;
+export const EVM_WORD_WIDTH_IN_BITS = 256;
+export const HEX_BASE = 16;
+export const DEC_BASE = 10;
+export const BIN_BASE = 2;
+export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
+export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
+export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
-- 
cgit v1.2.3


From dcc439c2e3a756af75889ddf3b22146322d1d97d Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 16:28:37 -0800
Subject: Ran prettier

---
 packages/utils/src/abi_encoder/evm_data_types/address.ts      | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index aab5a0605..9ae22bd9c 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -13,7 +13,7 @@ export class Address extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
-        Address._ADDRESS_SIZE_IN_BYTES;
+    Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
         return type === 'address';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 77dde1333..9a2a99ec7 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -46,7 +46,7 @@ export class StaticBytes extends PayloadDataType {
         if (valueBuf.byteLength > this._width) {
             throw new Error(
                 `Tried to assign ${value} (${
-                valueBuf.byteLength
+                    valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
         } else if (value.length % 2 !== 0) {
-- 
cgit v1.2.3


From 978a58105cd2d2f5d6ee3bcd870218fd357fb010 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 16:34:41 -0800
Subject: Prepended `front` to function names in Queue

---
 packages/utils/src/abi_encoder/calldata/calldata.ts     | 14 +++++++-------
 packages/utils/src/abi_encoder/calldata/raw_calldata.ts |  6 +++---
 packages/utils/src/abi_encoder/utils/queue.ts           |  8 ++++----
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 154a81b7f..3b85f821b 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -19,7 +19,7 @@ export class Calldata {
 
         // Base Case
         if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) {
-            blockQueue.push(block);
+            blockQueue.pushBack(block);
             return blockQueue;
         }
 
@@ -38,9 +38,9 @@ export class Calldata {
             if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) {
                 const dependency = member.getDependency();
                 if (dependency instanceof CalldataBlocks.MemberCalldataBlock) {
-                    blockQueue.merge(Calldata._createQueue(dependency));
+                    blockQueue.mergeBack(Calldata._createQueue(dependency));
                 } else {
-                    blockQueue.push(dependency);
+                    blockQueue.pushBack(dependency);
                 }
             }
         });
@@ -100,7 +100,7 @@ export class Calldata {
         const offsetQueue = Calldata._createQueue(this._root);
         let block: CalldataBlock | undefined;
         let offset = 0;
-        for (block = offsetQueue.pop(); block !== undefined; block = offsetQueue.pop()) {
+        for (block = offsetQueue.popFront(); block !== undefined; block = offsetQueue.popFront()) {
             block.setOffset(offset);
             offset += block.getSizeInBytes();
         }
@@ -140,9 +140,9 @@ export class Calldata {
 
         let block: CalldataBlock | undefined;
         let offset = 0;
-        const functionBlock = valueQueue.peek();
+        const functionBlock = valueQueue.peekFront();
         const functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
-        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
+        for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) {
             // Process each block 1 word at a time
             const size = block.getSizeInBytes();
             const name = block.getName();
@@ -212,7 +212,7 @@ export class Calldata {
         const valueQueue = Calldata._createQueue(this._root);
         const valueBufs: Buffer[] = [selectorBuffer];
         let block: CalldataBlock | undefined;
-        for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) {
+        for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) {
             valueBufs.push(block.toBuffer());
         }
 
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index 27a59c6a3..9e72bbd62 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -26,7 +26,7 @@ export class RawCalldata {
         }
 
         this._scopes = new Queue<number>();
-        this._scopes.push(RawCalldata._INITIAL_OFFSET);
+        this._scopes.pushBack(RawCalldata._INITIAL_OFFSET);
         this._offset = RawCalldata._INITIAL_OFFSET;
     }
 
@@ -60,7 +60,7 @@ export class RawCalldata {
     }
 
     public endScope(): void {
-        this._scopes.pop();
+        this._scopes.popFront();
     }
 
     public getOffset(): number {
@@ -68,7 +68,7 @@ export class RawCalldata {
     }
 
     public toAbsoluteOffset(relativeOffset: number): number {
-        const scopeOffset = this._scopes.peek();
+        const scopeOffset = this._scopes.peekFront();
         if (scopeOffset === undefined) {
             throw new Error(`Tried to access undefined scope.`);
         }
diff --git a/packages/utils/src/abi_encoder/utils/queue.ts b/packages/utils/src/abi_encoder/utils/queue.ts
index 3309d8ba2..53afb7e11 100644
--- a/packages/utils/src/abi_encoder/utils/queue.ts
+++ b/packages/utils/src/abi_encoder/utils/queue.ts
@@ -1,7 +1,7 @@
 export class Queue<T> {
     private _store: T[] = [];
 
-    public push(val: T): void {
+    public pushBack(val: T): void {
         this._store.push(val);
     }
 
@@ -9,7 +9,7 @@ export class Queue<T> {
         this._store.unshift(val);
     }
 
-    public pop(): T | undefined {
+    public popFront(): T | undefined {
         return this._store.shift();
     }
 
@@ -21,7 +21,7 @@ export class Queue<T> {
         return backElement;
     }
 
-    public merge(q: Queue<T>): void {
+    public mergeBack(q: Queue<T>): void {
         this._store = this._store.concat(q._store);
     }
 
@@ -33,7 +33,7 @@ export class Queue<T> {
         return this._store;
     }
 
-    public peek(): T | undefined {
+    public peekFront(): T | undefined {
         return this._store.length >= 0 ? this._store[0] : undefined;
     }
 }
-- 
cgit v1.2.3


From c638151b73289fc936bb7d4323711d1954cc4fcb Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 20 Nov 2018 16:51:56 -0800
Subject: Some minor cleanup in ABI Encoder

---
 .../abi_encoder/abstract_data_types/data_type.ts   |  2 +-
 .../abstract_data_types/dependent_data_type.ts     |  7 +++--
 .../abi_encoder/abstract_data_types/interfaces.ts  |  4 +++
 .../abstract_data_types/member_data_type.ts        | 36 ++++++++++------------
 .../abstract_data_types/payload_data_type.ts       |  2 +-
 5 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index a6adeb23b..c83f2085e 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -32,7 +32,7 @@ export abstract class DataType {
             calldata.setSelector(selector);
         }
         const block = this.generateCalldataBlock(value);
-        calldata.setRoot(block); // @TODO CHANGE
+        calldata.setRoot(block);
         const calldataHex = calldata.toHexString();
         return calldataHex;
     }
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
index f4992dd0f..7649b1836 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
@@ -28,16 +28,17 @@ export abstract class DependentDataType extends DataType {
         const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const parentName = parentBlock ? parentBlock.getName() : '';
         const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock);
         return block;
     }
 
     public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
         const destinationOffsetBuf = calldata.popWord();
-        const currentOffset = calldata.getOffset();
-        const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), Constants.HEX_BASE);
+        const destinationOffsetHex = ethUtil.bufferToHex(destinationOffsetBuf);
+        const destinationOffsetRelative = parseInt(destinationOffsetHex, Constants.HEX_BASE);
         const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
+        const currentOffset = calldata.getOffset();
         calldata.setOffset(destinationOffsetAbsolute);
         const value = this._dependency.generateValue(calldata, rules);
         calldata.setOffset(currentOffset);
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
index 2ae92659c..9e2a94522 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
@@ -14,3 +14,7 @@ export interface DataTypeStaticInterface {
     encodeValue: (value: any) => Buffer;
     decodeValue: (rawCalldata: RawCalldata) => any;
 }
+
+export interface MemberIndexByName {
+    [key: string]: number;
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
index 318564e21..dacdbf8af 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
@@ -9,16 +9,12 @@ import { DecodingRules } from '../utils/rules';
 
 import { DataType } from './data_type';
 import { DependentDataType } from './dependent_data_type';
-import { DataTypeFactory } from './interfaces';
-
-interface MemberMap {
-    [key: string]: number;
-}
+import { DataTypeFactory, MemberIndexByName } from './interfaces';
 
 export abstract class MemberDataType extends DataType {
     protected readonly _arrayLength: number | undefined;
     protected readonly _arrayElementType: string | undefined;
-    private readonly _memberMap: MemberMap;
+    private readonly _memberIndexByName: MemberIndexByName;
     private readonly _members: DataType[];
     private readonly _isArray: boolean;
 
@@ -30,15 +26,15 @@ export abstract class MemberDataType extends DataType {
         arrayElementType?: string,
     ) {
         super(dataItem, factory);
-        this._memberMap = {};
+        this._memberIndexByName = {};
         this._members = [];
         this._isArray = isArray;
         this._arrayLength = arrayLength;
         this._arrayElementType = arrayElementType;
         if (isArray && arrayLength !== undefined) {
-            [this._members, this._memberMap] = this._createMembersWithLength(dataItem, arrayLength);
+            [this._members, this._memberIndexByName] = this._createMembersWithLength(dataItem, arrayLength);
         } else if (!isArray) {
-            [this._members, this._memberMap] = this._createMembersWithKeys(dataItem);
+            [this._members, this._memberIndexByName] = this._createMembersWithKeys(dataItem);
         }
     }
 
@@ -65,7 +61,7 @@ export abstract class MemberDataType extends DataType {
         let value: any[] | object;
         if (rules.structsAsObjects && !this._isArray) {
             value = {};
-            _.each(this._memberMap, (idx: number, key: string) => {
+            _.each(this._memberIndexByName, (idx: number, key: string) => {
                 const member = this._members[idx];
                 const memberValue = member.generateValue(calldata, rules);
                 (value as { [key: string]: any })[key] = memberValue;
@@ -149,14 +145,14 @@ export abstract class MemberDataType extends DataType {
             parentName,
         );
         const memberBlocks: CalldataBlock[] = [];
-        const childMap = _.cloneDeep(this._memberMap);
+        const childMap = _.cloneDeep(this._memberIndexByName);
         _.forOwn(obj, (value: any, key: string) => {
             if (!(key in childMap)) {
                 throw new Error(
                     `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
                 );
             }
-            const block = this._members[this._memberMap[key]].generateCalldataBlock(value, methodBlock);
+            const block = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, methodBlock);
             memberBlocks.push(block);
             delete childMap[key];
         });
@@ -182,14 +178,14 @@ export abstract class MemberDataType extends DataType {
         return signature;
     }
 
-    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] {
         // Sanity check
         if (dataItem.components === undefined) {
             throw new Error(`Expected components`);
         }
 
         const members: DataType[] = [];
-        const memberMap: MemberMap = {};
+        const memberIndexByName: MemberIndexByName = {};
         _.each(dataItem.components, (memberItem: DataItem) => {
             const childDataItem: DataItem = {
                 type: memberItem.type,
@@ -200,16 +196,16 @@ export abstract class MemberDataType extends DataType {
                 childDataItem.components = components;
             }
             const child = this.getFactory().create(childDataItem, this);
-            memberMap[memberItem.name] = members.length;
+            memberIndexByName[memberItem.name] = members.length;
             members.push(child);
         });
 
-        return [members, memberMap];
+        return [members, memberIndexByName];
     }
 
-    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] {
         const members: DataType[] = [];
-        const memberMap: MemberMap = {};
+        const memberIndexByName: MemberIndexByName = {};
         const range = _.range(length);
         _.each(range, (idx: number) => {
             const childDataItem: DataItem = {
@@ -221,10 +217,10 @@ export abstract class MemberDataType extends DataType {
                 childDataItem.components = components;
             }
             const child = this.getFactory().create(childDataItem, this);
-            memberMap[idx.toString(Constants.DEC_BASE)] = members.length;
+            memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length;
             members.push(child);
         });
 
-        return [members, memberMap];
+        return [members, memberIndexByName];
     }
 }
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
index 767e64f51..fa420bc74 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
@@ -19,7 +19,7 @@ export abstract class PayloadDataType extends DataType {
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const parentName = parentBlock ? parentBlock.getName() : '';
         const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
         return block;
     }
-- 
cgit v1.2.3


From dc7092e1eb11ff9844efe02e367ef37592f38c55 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 15:32:13 -0800
Subject: Removed mapDataItemToDataType from Factory. Now its just ::create()

---
 .../abi_encoder/abstract_data_types/interfaces.ts  |  1 -
 .../utils/src/abi_encoder/evm_data_type_factory.ts | 42 ++++++++++------------
 .../utils/src/abi_encoder/evm_data_types/array.ts  |  2 +-
 .../utils/src/abi_encoder/evm_data_types/method.ts | 22 ++++--------
 4 files changed, 25 insertions(+), 42 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
index 9e2a94522..bd4d2effd 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
@@ -6,7 +6,6 @@ import { DataType } from './data_type';
 
 export interface DataTypeFactory {
     create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
-    mapDataItemToDataType: (dataItem: DataItem) => DataType;
 }
 
 export interface DataTypeStaticInterface {
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index 5d37acad9..bfe457367 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -82,42 +82,36 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         return EvmDataTypeFactory._instance;
     }
 
-    public mapDataItemToDataType(dataItem: DataItem): DataType {
+    public create(dataItem: DataItem, parentDataType?: DataType): DataType {
+        // Create data type
+        let dataType: undefined | DataType;
         if (Array.matchType(dataItem.type)) {
-            return new Array(dataItem);
+            dataType = new Array(dataItem);
         } else if (Address.matchType(dataItem.type)) {
-            return new Address(dataItem);
+            dataType = new Address(dataItem);
         } else if (Bool.matchType(dataItem.type)) {
-            return new Bool(dataItem);
+            dataType = new Bool(dataItem);
         } else if (Int.matchType(dataItem.type)) {
-            return new Int(dataItem);
+            dataType = new Int(dataItem);
         } else if (UInt.matchType(dataItem.type)) {
-            return new UInt(dataItem);
+            dataType = new UInt(dataItem);
         } else if (StaticBytes.matchType(dataItem.type)) {
-            return new StaticBytes(dataItem);
+            dataType = new StaticBytes(dataItem);
         } else if (Tuple.matchType(dataItem.type)) {
-            return new Tuple(dataItem);
+            dataType = new Tuple(dataItem);
         } else if (DynamicBytes.matchType(dataItem.type)) {
-            return new DynamicBytes(dataItem);
+            dataType = new DynamicBytes(dataItem);
         } else if (String.matchType(dataItem.type)) {
-            return new String(dataItem);
+            dataType = new String(dataItem);
         }
         // @TODO: Implement Fixed/UFixed types
-        throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-    }
-
-    public create(dataItem: DataItem, parentDataType?: DataType): DataType {
-        const dataType = this.mapDataItemToDataType(dataItem);
-        if (dataType.isStatic()) {
-            return dataType;
-        }
-
-        if (parentDataType === undefined) {
-            // @Todo -- will this work for return values?
-            throw new Error(`Trying to create a pointer`);
+        if (!dataType) {
+            throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+        } else if (parentDataType && !dataType.isStatic()) {
+            const pointerToDataType = new Pointer(dataType, parentDataType);
+            return pointerToDataType;
         }
-        const pointer = new Pointer(dataType, parentDataType);
-        return pointer;
+        return dataType;
     }
 
     private constructor() {}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 9963b6f32..dd8184fd0 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -44,7 +44,7 @@ export class Array extends MemberDataType {
         if (components !== undefined) {
             dataItem.components = components;
         }
-        const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
+        const elementDataType = this.getFactory().create(dataItem);
         const type = elementDataType.getSignature();
         if (this._arrayLength === undefined) {
             return `${type}[]`;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index 50d676b4a..671b80890 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -7,7 +7,6 @@ import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
-import { StaticBytes } from './static_bytes';
 import { Tuple } from './tuple';
 
 export class Method extends MemberDataType {
@@ -16,19 +15,14 @@ export class Method extends MemberDataType {
 
     private readonly _methodSignature: string;
     private readonly _methodSelector: string;
-    private readonly _returnDataTypes: DataType[];
-    private readonly _returnDataItem: DataItem;
+    private readonly _returnDataType: DataType;
 
     public constructor(abi: MethodAbi, dataTypeFactory: DataTypeFactory) {
         super({ type: 'method', name: abi.name, components: abi.inputs }, dataTypeFactory);
         this._methodSignature = this._computeSignature();
         this.selector = this._methodSelector = this._computeSelector();
-        this._returnDataTypes = [];
-        this._returnDataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
-        const dummy = new StaticBytes({ type: 'byte', name: 'DUMMY' }, dataTypeFactory); // @TODO TMP
-        _.each(abi.outputs, (dataItem: DataItem) => {
-            this._returnDataTypes.push(this.getFactory().create(dataItem, dummy));
-        });
+        const returnDataItem: DataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
+        this._returnDataType = new Tuple(returnDataItem, this.getFactory());
     }
 
     public encode(value: any, rules?: EncodingRules): string {
@@ -48,18 +42,14 @@ export class Method extends MemberDataType {
     }
 
     public encodeReturnValues(value: any, rules?: EncodingRules): string {
-        const returnDataType = new Tuple(this._returnDataItem, this.getFactory());
-        const returndata = returnDataType.encode(value, rules);
-        return returndata;
+        const returnData = this._returnDataType.encode(value, rules);
+        return returnData;
     }
 
     public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
-        const returnValues: any[] = [];
         const rules_: DecodingRules = rules ? rules : { structsAsObjects: false };
         const rawReturnData = new RawCalldata(returndata, false);
-        _.each(this._returnDataTypes, (dataType: DataType) => {
-            returnValues.push(dataType.generateValue(rawReturnData, rules_));
-        });
+        const returnValues = this._returnDataType.generateValue(rawReturnData, rules_);
         return returnValues;
     }
 
-- 
cgit v1.2.3


From dd8bb6d08b6e837304a76e9707b79e070f951e4e Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 15:38:29 -0800
Subject: Made default encoding/decoding rules global to all modules in encoder

---
 .../abi_encoder/abstract_data_types/data_type.ts   |  7 +++----
 .../utils/src/abi_encoder/evm_data_types/method.ts | 23 +++++++++++-----------
 packages/utils/src/abi_encoder/utils/constants.ts  |  4 ++++
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index c83f2085e..dd166b19c 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -2,13 +2,12 @@ import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { Calldata, CalldataBlock, RawCalldata } from '../calldata';
+import * as Constants from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { DataTypeFactory } from './interfaces';
 
 export abstract class DataType {
-    private static readonly _DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
-    private static readonly _DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
     private readonly _dataItem: DataItem;
     private readonly _factory: DataTypeFactory;
 
@@ -26,7 +25,7 @@ export abstract class DataType {
     }
 
     public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = rules ? rules : DataType._DEFAULT_ENCODING_RULES;
+        const rules_ = rules ? rules : Constants.DEFAULT_ENCODING_RULES;
         const calldata = new Calldata(rules_);
         if (selector) {
             calldata.setSelector(selector);
@@ -39,7 +38,7 @@ export abstract class DataType {
 
     public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
         const rawCalldata = new RawCalldata(calldata, hasSelector);
-        const rules_ = rules ? rules : DataType._DEFAULT_DECODING_RULES;
+        const rules_ = rules ? rules : Constants.DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index 671b80890..2faffd44e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -10,30 +10,28 @@ import { DecodingRules, EncodingRules } from '../utils/rules';
 import { Tuple } from './tuple';
 
 export class Method extends MemberDataType {
-    // TMP
-    public selector: string;
-
     private readonly _methodSignature: string;
     private readonly _methodSelector: string;
     private readonly _returnDataType: DataType;
 
     public constructor(abi: MethodAbi, dataTypeFactory: DataTypeFactory) {
-        super({ type: 'method', name: abi.name, components: abi.inputs }, dataTypeFactory);
+        const methodDataItem = { type: 'method', name: abi.name, components: abi.inputs };
+        super(methodDataItem, dataTypeFactory);
         this._methodSignature = this._computeSignature();
-        this.selector = this._methodSelector = this._computeSelector();
+        this._methodSelector = this._computeSelector();
         const returnDataItem: DataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
         this._returnDataType = new Tuple(returnDataItem, this.getFactory());
     }
 
     public encode(value: any, rules?: EncodingRules): string {
-        const calldata = super.encode(value, rules, this.selector);
+        const calldata = super.encode(value, rules, this._methodSelector);
         return calldata;
     }
 
     public decode(calldata: string, rules?: DecodingRules): any[] | object {
-        if (!calldata.startsWith(this.selector)) {
+        if (!calldata.startsWith(this._methodSelector)) {
             throw new Error(
-                `Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`,
+                `Tried to decode calldata, but it was missing the function selector. Expected '${this._methodSelector}'.`,
             );
         }
         const hasSelector = true;
@@ -46,10 +44,11 @@ export class Method extends MemberDataType {
         return returnData;
     }
 
-    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
-        const rules_: DecodingRules = rules ? rules : { structsAsObjects: false };
-        const rawReturnData = new RawCalldata(returndata, false);
-        const returnValues = this._returnDataType.generateValue(rawReturnData, rules_);
+    public decodeReturnValues(returndata: string, rules_?: DecodingRules): any {
+        const rules: DecodingRules = rules_ ? rules_ : Constants.DEFAULT_DECODING_RULES;
+        const returnDataHasSelector = false;
+        const rawReturnData = new RawCalldata(returndata, returnDataHasSelector);
+        const returnValues = this._returnDataType.generateValue(rawReturnData, rules);
         return returnValues;
     }
 
diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts
index 3d85fbdb8..05c6783e7 100644
--- a/packages/utils/src/abi_encoder/utils/constants.ts
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -1,3 +1,5 @@
+import { DecodingRules, EncodingRules } from './rules';
+
 export const EVM_WORD_WIDTH_IN_BYTES = 32;
 export const EVM_WORD_WIDTH_IN_BITS = 256;
 export const HEX_BASE = 16;
@@ -6,3 +8,5 @@ export const BIN_BASE = 2;
 export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
 export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
 export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
+export const DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
+export const DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
-- 
cgit v1.2.3


From 173fc1dcefa266704dd80de6335c03b73b7d8702 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 15:50:49 -0800
Subject: Moved encoder selector check into DataType

---
 .../src/abi_encoder/abstract_data_types/data_type.ts     |  8 +++++++-
 packages/utils/src/abi_encoder/evm_data_types/method.ts  | 16 +++-------------
 2 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index dd166b19c..450080353 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -36,7 +36,13 @@ export abstract class DataType {
         return calldataHex;
     }
 
-    public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
+    public decode(calldata: string, rules?: DecodingRules, selector?: string): any {
+        if (selector && !calldata.startsWith(selector)) {
+            throw new Error(
+                `Tried to decode calldata, but it was missing the function selector. Expected '${selector}'.`,
+            );
+        }
+        const hasSelector = selector ? true : false;
         const rawCalldata = new RawCalldata(calldata, hasSelector);
         const rules_ = rules ? rules : Constants.DEFAULT_DECODING_RULES;
         const value = this.generateValue(rawCalldata, rules_);
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index 2faffd44e..f2e417485 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -3,7 +3,6 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { DataType, DataTypeFactory, MemberDataType } from '../abstract_data_types';
-import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
@@ -29,13 +28,7 @@ export class Method extends MemberDataType {
     }
 
     public decode(calldata: string, rules?: DecodingRules): any[] | object {
-        if (!calldata.startsWith(this._methodSelector)) {
-            throw new Error(
-                `Tried to decode calldata, but it was missing the function selector. Expected '${this._methodSelector}'.`,
-            );
-        }
-        const hasSelector = true;
-        const value = super.decode(calldata, rules, hasSelector);
+        const value = super.decode(calldata, rules, this._methodSelector);
         return value;
     }
 
@@ -44,11 +37,8 @@ export class Method extends MemberDataType {
         return returnData;
     }
 
-    public decodeReturnValues(returndata: string, rules_?: DecodingRules): any {
-        const rules: DecodingRules = rules_ ? rules_ : Constants.DEFAULT_DECODING_RULES;
-        const returnDataHasSelector = false;
-        const rawReturnData = new RawCalldata(returndata, returnDataHasSelector);
-        const returnValues = this._returnDataType.generateValue(rawReturnData, rules);
+    public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
+        const returnValues = this._returnDataType.decode(returndata, rules);
         return returnValues;
     }
 
-- 
cgit v1.2.3


From 58a2dfbc4d191ea21e6a749371e586dcff3b3239 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 17:04:50 -0800
Subject: Final rounds on evm data types

---
 .../src/abi_encoder/evm_data_types/static_bytes.ts | 58 ++++++++++++----------
 .../utils/src/abi_encoder/evm_data_types/string.ts | 33 +++++++-----
 .../utils/src/abi_encoder/evm_data_types/tuple.ts  |  8 +--
 packages/utils/src/abi_encoder/utils/queue.ts      |  2 +-
 4 files changed, 59 insertions(+), 42 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 9a2a99ec7..afa9afdf2 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -11,7 +11,6 @@ export class StaticBytes extends PayloadDataType {
     private static readonly _matcher = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
     );
-
     private static readonly _DEFAULT_WIDTH = 1;
     private readonly _width: number;
 
@@ -19,16 +18,20 @@ export class StaticBytes extends PayloadDataType {
         return StaticBytes._matcher.test(type);
     }
 
+    private static _decodeWidthFromType(type: string): number {
+        const matches = StaticBytes._matcher.exec(type);
+        const width = (matches !== null && matches.length === 3 && matches[2] !== undefined)
+            ? parseInt(matches[2], Constants.DEC_BASE)
+            : StaticBytes._DEFAULT_WIDTH;
+        return width;
+    }
+
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         super(dataItem, dataTypeFactory, StaticBytes._SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = StaticBytes._matcher.exec(dataItem.type);
         if (!StaticBytes.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate Byte with bad input: ${dataItem}`);
+            throw new Error(`Tried to instantiate Static Bytes with bad input: ${dataItem}`);
         }
-        this._width =
-            matches !== null && matches.length === 3 && matches[2] !== undefined
-                ? parseInt(matches[2], Constants.DEC_BASE)
-                : StaticBytes._DEFAULT_WIDTH;
+        this._width = StaticBytes._decodeWidthFromType(dataItem.type);
     }
 
     public getSignature(): string {
@@ -37,11 +40,30 @@ export class StaticBytes extends PayloadDataType {
     }
 
     public encodeValue(value: string | Buffer): Buffer {
-        // Sanity check if string
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
+        // 1/2 Convert value into a buffer and do bounds checking
+        this._sanityCheckValue(value);
+        const valueBuf = ethUtil.toBuffer(value);
+        // 2/2 Store value as hex
+        const valuePadded = ethUtil.setLengthRight(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        return valuePadded;
+    }
+
+    public decodeValue(calldata: RawCalldata): string {
+        const valueBufPadded = calldata.popWord();
+        const valueBuf = valueBufPadded.slice(0, this._width);
+        const value = ethUtil.bufferToHex(valueBuf);
+        this._sanityCheckValue(value);
+        return value;
+    }
+    
+    private _sanityCheckValue(value: string | Buffer): void {
+        if (typeof value === 'string') {
+            if (!value.startsWith('0x')) {
+                throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
+            } else if (value.length % 2 !== 0) {
+                throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+            }
         }
-        // Convert value into a buffer and do bounds checking
         const valueBuf = ethUtil.toBuffer(value);
         if (valueBuf.byteLength > this._width) {
             throw new Error(
@@ -49,20 +71,6 @@ export class StaticBytes extends PayloadDataType {
                     valueBuf.byteLength
                 } bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
             );
-        } else if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
         }
-
-        // Store value as hex
-        const evmWordWidth = 32;
-        const paddedValue = ethUtil.setLengthRight(valueBuf, evmWordWidth);
-        return paddedValue;
-    }
-
-    public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(0, this._width);
-        const value = ethUtil.bufferToHex(valueBuf);
-        return value;
     }
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 47ad7cb97..15b93e447 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -13,7 +13,7 @@ export class String extends PayloadDataType {
     public static matchType(type: string): boolean {
         return type === 'string';
     }
-
+    
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         super(dataItem, dataTypeFactory, String._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!String.matchType(dataItem.type)) {
@@ -22,21 +22,30 @@ export class String extends PayloadDataType {
     }
 
     public encodeValue(value: string): Buffer {
-        const wordsForValue = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
-        const valueBuf = ethUtil.setLengthRight(new Buffer(value), paddedDynamicBytesForValue);
-        const lengthBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value.length), Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const encodedValueBuf = Buffer.concat([lengthBuf, valueBuf]);
+        // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
+        // 1/3 Construct the length
+        const wordsToStoreValuePadded = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const bytesToStoreValuePadded = wordsToStoreValuePadded * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const lengthBuf = ethUtil.toBuffer(value.length);
+        const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        // 2/3 Construct the value
+        const valueBuf = new Buffer(value);
+        const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
+        // 3/3 Combine length and value
+        const encodedValueBuf = Buffer.concat([lengthBufPadded, valueBufPadded]);
         return encodedValueBuf;
     }
 
     public decodeValue(calldata: RawCalldata): string {
-        const lengthBuf = calldata.popWord();
-        const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, Constants.HEX_BASE);
-        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
+        // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
+        // 1/2 Decode length
+        const lengthBufPadded = calldata.popWord();
+        const lengthHexPadded = ethUtil.bufferToHex(lengthBufPadded);
+        const length = parseInt(lengthHexPadded, Constants.HEX_BASE);
+        // 2/2 Decode value
+        const wordsToStoreValuePadded = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
+        const valueBuf = valueBufPadded.slice(0, length);
         const value = valueBuf.toString('ascii');
         return value;
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 4a90e375a..89dd6604d 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -3,8 +3,8 @@ import { DataItem } from 'ethereum-types';
 import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
 
 export class Tuple extends MemberDataType {
-    private readonly _tupleSignature: string;
-
+    private readonly _signature: string;
+    
     public static matchType(type: string): boolean {
         return type === 'tuple';
     }
@@ -14,10 +14,10 @@ export class Tuple extends MemberDataType {
         if (!Tuple.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
         }
-        this._tupleSignature = this._computeSignatureOfMembers();
+        this._signature = this._computeSignatureOfMembers();
     }
 
     public getSignature(): string {
-        return this._tupleSignature;
+        return this._signature;
     }
 }
diff --git a/packages/utils/src/abi_encoder/utils/queue.ts b/packages/utils/src/abi_encoder/utils/queue.ts
index 53afb7e11..506a0b56e 100644
--- a/packages/utils/src/abi_encoder/utils/queue.ts
+++ b/packages/utils/src/abi_encoder/utils/queue.ts
@@ -32,7 +32,7 @@ export class Queue<T> {
     public getStore(): T[] {
         return this._store;
     }
-
+    
     public peekFront(): T | undefined {
         return this._store.length >= 0 ? this._store[0] : undefined;
     }
-- 
cgit v1.2.3


From d2d89adbddaec435ddb65545a86fc4dc981de521 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 17:12:21 -0800
Subject: Abstracted out encoding/decoding of numeric values into its own
 utility. Could be useful elsewhere.

---
 .../utils/src/abi_encoder/evm_data_types/array.ts  |   6 +-
 .../utils/src/abi_encoder/evm_data_types/int.ts    |   6 +-
 .../utils/src/abi_encoder/evm_data_types/number.ts |  71 ++------------
 .../src/abi_encoder/evm_data_types/static_bytes.ts |   8 +-
 .../utils/src/abi_encoder/evm_data_types/string.ts |   2 +-
 .../utils/src/abi_encoder/evm_data_types/tuple.ts  |   2 +-
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |   6 +-
 packages/utils/src/abi_encoder/utils/math.ts       | 103 +++++++++++++++++++++
 packages/utils/src/abi_encoder/utils/queue.ts      |   2 +-
 9 files changed, 125 insertions(+), 81 deletions(-)
 create mode 100644 packages/utils/src/abi_encoder/utils/math.ts

diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index dd8184fd0..527cdadfe 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -4,17 +4,17 @@ import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
 import * as Constants from '../utils/constants';
 
 export class Array extends MemberDataType {
-    private static readonly _matcher = RegExp('^(.+)\\[([0-9]*)\\]$');
+    private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$');
     private readonly _arraySignature: string;
     private readonly _elementType: string;
 
     public static matchType(type: string): boolean {
-        return Array._matcher.test(type);
+        return Array._MATCHER.test(type);
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         // Sanity check
-        const matches = Array._matcher.exec(dataItem.type);
+        const matches = Array._MATCHER.exec(dataItem.type);
         if (matches === null || matches.length !== 3) {
             throw new Error(`Could not parse array: ${dataItem.type}`);
         } else if (matches[1] === undefined) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index ec41b9cfc..457c41b28 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -7,16 +7,16 @@ import { DataTypeFactory } from '../abstract_data_types';
 import { Number } from './number';
 
 export class Int extends Number {
-    private static readonly _matcher = RegExp(
+    private static readonly _MATCHER = RegExp(
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
 
     public static matchType(type: string): boolean {
-        return Int._matcher.test(type);
+        return Int._MATCHER.test(type);
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, Int._matcher, dataTypeFactory);
+        super(dataItem, Int._MATCHER, dataTypeFactory);
     }
 
     public getMaxValue(): BigNumber {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/number.ts b/packages/utils/src/abi_encoder/evm_data_types/number.ts
index 86acdce07..053a574e3 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/number.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/number.ts
@@ -1,11 +1,11 @@
 import { DataItem } from 'ethereum-types';
-import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
 import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
+import * as EncoderMath from '../utils/math';
 
 export abstract class Number extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
@@ -25,73 +25,14 @@ export abstract class Number extends PayloadDataType {
                 : (this._width = Number._DEFAULT_WIDTH);
     }
 
-    public encodeValue(value_: BigNumber | string | number): Buffer {
-        const value = new BigNumber(value_, 10);
-        if (value.greaterThan(this.getMaxValue())) {
-            throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`);
-        } else if (value.lessThan(this.getMinValue())) {
-            throw new Error(`Tried to assign value of ${value}, which exceeds min value of ${this.getMinValue()}`);
-        }
-
-        let valueBuf: Buffer;
-        if (value.greaterThanOrEqualTo(0)) {
-            valueBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${value.toString(Constants.HEX_BASE)}`),
-                Constants.EVM_WORD_WIDTH_IN_BYTES,
-            );
-        } else {
-            // BigNumber can't write a negative hex value, so we use twos-complement conversion to do it ourselves.
-            // Step 1/3: Convert value to positive binary string
-            const binBase = 2;
-            const valueBin = value.times(-1).toString(binBase);
-
-            // Step 2/3: Invert binary value
-            let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
-            _.each(valueBin, (bit: string) => {
-                invertedValueBin += bit === '1' ? '0' : '1';
-            });
-            const invertedValue = new BigNumber(invertedValueBin, binBase);
-
-            // Step 3/3: Add 1 to inverted value
-            // The result is the two's-complement represent of the input value.
-            const negativeValue = invertedValue.plus(1);
-
-            // Convert the negated value to a hex string
-            valueBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${negativeValue.toString(Constants.HEX_BASE)}`),
-                Constants.EVM_WORD_WIDTH_IN_BYTES,
-            );
-        }
-
-        return valueBuf;
+    public encodeValue(value: BigNumber | string | number): Buffer {
+        const encodedValue = EncoderMath.safeEncodeNumericValue(value, this.getMinValue(), this.getMaxValue());
+        return encodedValue;
     }
 
     public decodeValue(calldata: RawCalldata): BigNumber {
-        const paddedValueBuf = calldata.popWord();
-        const paddedValueHex = ethUtil.bufferToHex(paddedValueBuf);
-        let value = new BigNumber(paddedValueHex, 16);
-        if (this.getMinValue().lessThan(0)) {
-            // Check if we're negative
-            const valueBin = value.toString(Constants.BIN_BASE);
-            if (valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1')) {
-                // Negative
-                // Step 1/3: Invert binary value
-                let invertedValueBin = '';
-                _.each(valueBin, (bit: string) => {
-                    invertedValueBin += bit === '1' ? '0' : '1';
-                });
-                const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
-
-                // Step 2/3: Add 1 to inverted value
-                // The result is the two's-complement represent of the input value.
-                const positiveValue = invertedValue.plus(1);
-
-                // Step 3/3: Invert positive value
-                const negativeValue = positiveValue.times(-1);
-                value = negativeValue;
-            }
-        }
-
+        const valueBuf = calldata.popWord();
+        const value = EncoderMath.safeDecodeNumericValue(valueBuf, this.getMinValue(), this.getMaxValue());
         return value;
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index afa9afdf2..0d01e6105 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -8,18 +8,18 @@ import * as Constants from '../utils/constants';
 
 export class StaticBytes extends PayloadDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    private static readonly _matcher = RegExp(
+    private static readonly _MATCHER = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
     );
     private static readonly _DEFAULT_WIDTH = 1;
     private readonly _width: number;
 
     public static matchType(type: string): boolean {
-        return StaticBytes._matcher.test(type);
+        return StaticBytes._MATCHER.test(type);
     }
 
     private static _decodeWidthFromType(type: string): number {
-        const matches = StaticBytes._matcher.exec(type);
+        const matches = StaticBytes._MATCHER.exec(type);
         const width = (matches !== null && matches.length === 3 && matches[2] !== undefined)
             ? parseInt(matches[2], Constants.DEC_BASE)
             : StaticBytes._DEFAULT_WIDTH;
@@ -55,7 +55,7 @@ export class StaticBytes extends PayloadDataType {
         this._sanityCheckValue(value);
         return value;
     }
-    
+
     private _sanityCheckValue(value: string | Buffer): void {
         if (typeof value === 'string') {
             if (!value.startsWith('0x')) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 15b93e447..428ea21db 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -13,7 +13,7 @@ export class String extends PayloadDataType {
     public static matchType(type: string): boolean {
         return type === 'string';
     }
-    
+
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         super(dataItem, dataTypeFactory, String._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!String.matchType(dataItem.type)) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 89dd6604d..63d9dfa9e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -4,7 +4,7 @@ import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
 
 export class Tuple extends MemberDataType {
     private readonly _signature: string;
-    
+
     public static matchType(type: string): boolean {
         return type === 'tuple';
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index ced3ef08b..c2b6e214a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -7,16 +7,16 @@ import { DataTypeFactory } from '../abstract_data_types';
 import { Number } from './number';
 
 export class UInt extends Number {
-    private static readonly _matcher = RegExp(
+    private static readonly _MATCHER = RegExp(
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
 
     public static matchType(type: string): boolean {
-        return UInt._matcher.test(type);
+        return UInt._MATCHER.test(type);
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, UInt._matcher, dataTypeFactory);
+        super(dataItem, UInt._MATCHER, dataTypeFactory);
     }
 
     public getMaxValue(): BigNumber {
diff --git a/packages/utils/src/abi_encoder/utils/math.ts b/packages/utils/src/abi_encoder/utils/math.ts
new file mode 100644
index 000000000..8d21ada0a
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/math.ts
@@ -0,0 +1,103 @@
+import BigNumber from 'bignumber.js';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import * as Constants from '../utils/constants';
+
+function sanityCheckBigNumberRange(value_: BigNumber | string | number, minValue: BigNumber, maxValue: BigNumber): void {
+    const value = new BigNumber(value_, 10);
+    if (value.greaterThan(maxValue)) {
+        throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${maxValue}`);
+    } else if (value.lessThan(minValue)) {
+        throw new Error(`Tried to assign value of ${value}, which exceeds min value of ${minValue}`);
+    }
+}
+function bigNumberToPaddedBuffer(value: BigNumber): Buffer {
+    const valueHex = `0x${value.toString(Constants.HEX_BASE)}`;
+    const valueBuf = ethUtil.toBuffer(valueHex);
+    const valueBufPadded = ethUtil.setLengthLeft(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+    return valueBufPadded;
+}
+/**
+ * Takes a numeric value and returns its ABI-encoded value
+ * @param value_    The value to encode.
+ * @return ABI Encoded value
+ */
+export function encodeNumericValue(value_: BigNumber | string | number): Buffer {
+    const value = new BigNumber(value_, 10);
+    // Case 1/2: value is non-negative
+    if (value.greaterThanOrEqualTo(0)) {
+        const encodedPositiveValue = bigNumberToPaddedBuffer(value);
+        return encodedPositiveValue;
+    }
+    // Case 2/2: Value is negative
+    // Use two's-complement to encode the value
+    // Step 1/3: Convert negative value to positive binary string
+    const valueBin = value.times(-1).toString(Constants.BIN_BASE);
+    // Step 2/3: Invert binary value
+    let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
+    _.each(valueBin, (bit: string) => {
+        invertedValueBin += bit === '1' ? '0' : '1';
+    });
+    const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
+    // Step 3/3: Add 1 to inverted value
+    const negativeValue = invertedValue.plus(1);
+    const encodedValue = bigNumberToPaddedBuffer(negativeValue);
+    return encodedValue;
+}
+/**
+ * Takes a numeric value and returns its ABI-encoded value.
+ * Performs an additional sanity check, given the min/max allowed value.
+ * @param value_    The value to encode.
+ * @return ABI Encoded value
+ */
+export function safeEncodeNumericValue(value: BigNumber | string | number, minValue: BigNumber, maxValue: BigNumber): Buffer {
+    sanityCheckBigNumberRange(value, minValue, maxValue);
+    const encodedValue = encodeNumericValue(value);
+    return encodedValue;
+}
+/**
+ * Takes an ABI-encoded numeric value and returns its decoded value as a BigNumber.
+ * @param encodedValue    The encoded numeric value.
+ * @param minValue        The minimum possible decoded value.
+ * @return ABI Decoded value
+ */
+export function decodeNumericValue(encodedValue: Buffer, minValue: BigNumber): BigNumber {
+    const valueHex = ethUtil.bufferToHex(encodedValue);
+    // Case 1/3: value is definitely non-negative because of numeric boundaries
+    const value = new BigNumber(valueHex, Constants.HEX_BASE);
+    if (!minValue.lessThan(0)) {
+        return value;
+    }
+    // Case 2/3: value is non-negative because there is no leading 1 (encoded as two's-complement)
+    const valueBin = value.toString(Constants.BIN_BASE);
+    const valueIsNegative = valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1');
+    if (!valueIsNegative) {
+        return value;
+    }
+    // Case 3/3: value is negative
+    // Step 1/3: Invert b inary value
+    let invertedValueBin = '';
+    _.each(valueBin, (bit: string) => {
+        invertedValueBin += bit === '1' ? '0' : '1';
+    });
+    const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
+    // Step 2/3: Add 1 to inverted value
+    // The result is the two's-complement representation of the input value.
+    const positiveValue = invertedValue.plus(1);
+    // Step 3/3: Invert positive value to get the negative value
+    const negativeValue = positiveValue.times(-1);
+    return negativeValue;
+}
+/**
+ * Takes an ABI-encoded numeric value and returns its decoded value as a BigNumber.
+ * Performs an additional sanity check, given the min/max allowed value.
+ * @param encodedValue    The encoded numeric value.
+ * @param minValue        The minimum possible decoded value.
+ * @return ABI Decoded value
+ */
+export function safeDecodeNumericValue(encodedValue: Buffer, minValue: BigNumber, maxValue: BigNumber): BigNumber {
+    const value = decodeNumericValue(encodedValue, minValue);
+    sanityCheckBigNumberRange(value, minValue, maxValue);
+    return value;
+}
diff --git a/packages/utils/src/abi_encoder/utils/queue.ts b/packages/utils/src/abi_encoder/utils/queue.ts
index 506a0b56e..53afb7e11 100644
--- a/packages/utils/src/abi_encoder/utils/queue.ts
+++ b/packages/utils/src/abi_encoder/utils/queue.ts
@@ -32,7 +32,7 @@ export class Queue<T> {
     public getStore(): T[] {
         return this._store;
     }
-    
+
     public peekFront(): T | undefined {
         return this._store.length >= 0 ? this._store[0] : undefined;
     }
-- 
cgit v1.2.3


From ebaf9dd275403cdecfb3364876737fcbcd0eab82 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 17:25:04 -0800
Subject: Removed abstract Number class.

---
 .../utils/src/abi_encoder/evm_data_types/int.ts    | 42 ++++++++++++++++-----
 .../utils/src/abi_encoder/evm_data_types/number.ts | 41 ---------------------
 .../utils/src/abi_encoder/evm_data_types/uint.ts   | 43 +++++++++++++++++-----
 3 files changed, 67 insertions(+), 59 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/evm_data_types/number.ts

diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 457c41b28..83aeacd66 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -2,29 +2,53 @@
 import { DataItem } from 'ethereum-types';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { RawCalldata } from '../calldata';
+import * as Constants from '../utils/constants';
+import * as EncoderMath from '../utils/math';
 
-import { Number } from './number';
-
-export class Int extends Number {
+export class Int extends PayloadDataType {
     private static readonly _MATCHER = RegExp(
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _MAX_WIDTH: number = 256;
+    private static readonly _DEFAULT_WIDTH: number = Int._MAX_WIDTH;
+    private _width: number;
+    private _minValue: BigNumber;
+    private _maxValue: BigNumber;
 
     public static matchType(type: string): boolean {
         return Int._MATCHER.test(type);
     }
 
+    private static _decodeWidthFromType(type: string): number {
+        const matches = Int._MATCHER.exec(type);
+        const width = (matches !== null && matches.length === 2 && matches[1] !== undefined)
+        ? parseInt(matches[1], Constants.DEC_BASE)
+        : Int._DEFAULT_WIDTH;
+        return width;
+    }
+
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, Int._MATCHER, dataTypeFactory);
+        super(dataItem, dataTypeFactory, Int._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!Int.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate Int with bad input: ${dataItem}`);
+        }
+        this._width = Int._decodeWidthFromType(dataItem.type);
+        this._minValue = new BigNumber(2).toPower(this._width - 1).times(-1);
+        this._maxValue = new BigNumber(2).toPower(this._width - 1).sub(1);
     }
 
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this._width - 1).sub(1);
+    public encodeValue(value: BigNumber | string | number): Buffer {
+        const encodedValue = EncoderMath.safeEncodeNumericValue(value, this._minValue, this._maxValue);
+        return encodedValue;
     }
 
-    public getMinValue(): BigNumber {
-        return new BigNumber(2).toPower(this._width - 1).times(-1);
+    public decodeValue(calldata: RawCalldata): BigNumber {
+        const valueBuf = calldata.popWord();
+        const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue);
+        return value;
     }
 
     public getSignature(): string {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/number.ts b/packages/utils/src/abi_encoder/evm_data_types/number.ts
deleted file mode 100644
index 053a574e3..000000000
--- a/packages/utils/src/abi_encoder/evm_data_types/number.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { DataItem } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
-import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
-import * as EncoderMath from '../utils/math';
-
-export abstract class Number extends PayloadDataType {
-    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
-    private static readonly _MAX_WIDTH: number = 256;
-    private static readonly _DEFAULT_WIDTH: number = Number._MAX_WIDTH;
-    protected _width: number;
-
-    constructor(dataItem: DataItem, matcher: RegExp, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, Number._SIZE_KNOWN_AT_COMPILE_TIME);
-        const matches = matcher.exec(dataItem.type);
-        if (matches === null) {
-            throw new Error(`Tried to instantiate Number with bad input: ${dataItem}`);
-        }
-        this._width =
-            matches !== null && matches.length === 2 && matches[1] !== undefined
-                ? parseInt(matches[1], Constants.DEC_BASE)
-                : (this._width = Number._DEFAULT_WIDTH);
-    }
-
-    public encodeValue(value: BigNumber | string | number): Buffer {
-        const encodedValue = EncoderMath.safeEncodeNumericValue(value, this.getMinValue(), this.getMaxValue());
-        return encodedValue;
-    }
-
-    public decodeValue(calldata: RawCalldata): BigNumber {
-        const valueBuf = calldata.popWord();
-        const value = EncoderMath.safeDecodeNumericValue(valueBuf, this.getMinValue(), this.getMaxValue());
-        return value;
-    }
-
-    public abstract getMaxValue(): BigNumber;
-    public abstract getMinValue(): BigNumber;
-}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index c2b6e214a..832ab075c 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -2,32 +2,57 @@
 import { DataItem } from 'ethereum-types';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { RawCalldata } from '../calldata';
+import * as Constants from '../utils/constants';
+import * as EncoderMath from '../utils/math';
 
-import { Number } from './number';
-
-export class UInt extends Number {
+export class UInt extends PayloadDataType {
     private static readonly _MATCHER = RegExp(
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
+    private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+    private static readonly _MAX_WIDTH: number = 256;
+    private static readonly _DEFAULT_WIDTH: number = UInt._MAX_WIDTH;
+    private _width: number;
+    private _minValue: BigNumber;
+    private _maxValue: BigNumber;
 
     public static matchType(type: string): boolean {
         return UInt._MATCHER.test(type);
     }
 
+    private static _decodeWidthFromType(type: string): number {
+        const matches = UInt._MATCHER.exec(type);
+        const width = (matches !== null && matches.length === 2 && matches[1] !== undefined)
+        ? parseInt(matches[1], Constants.DEC_BASE)
+        : UInt._DEFAULT_WIDTH;
+        return width;
+    }
+
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, UInt._MATCHER, dataTypeFactory);
+        super(dataItem, dataTypeFactory, UInt._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!UInt.matchType(dataItem.type)) {
+            throw new Error(`Tried to instantiate UInt with bad input: ${dataItem}`);
+        }
+        this._width = UInt._decodeWidthFromType(dataItem.type);
+        this._minValue = new BigNumber(0);
+        this._maxValue = new BigNumber(2).toPower(this._width).sub(1);
     }
 
-    public getMaxValue(): BigNumber {
-        return new BigNumber(2).toPower(this._width).sub(1);
+    public encodeValue(value: BigNumber | string | number): Buffer {
+        const encodedValue = EncoderMath.safeEncodeNumericValue(value, this._minValue, this._maxValue);
+        return encodedValue;
     }
 
-    public getMinValue(): BigNumber {
-        return new BigNumber(0);
+    public decodeValue(calldata: RawCalldata): BigNumber {
+        const valueBuf = calldata.popWord();
+        const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue);
+        return value;
     }
 
     public getSignature(): string {
         return `uint${this._width}`;
     }
 }
+
-- 
cgit v1.2.3


From acd364b71c8b3ddb6d4d75d8667cc7f50b18694d Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 17:37:14 -0800
Subject: Comments and inline documentation for dynamic bytes

---
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |  8 ++--
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    | 55 +++++++++++++---------
 .../utils/src/abi_encoder/evm_data_types/string.ts |  4 +-
 .../utils/test/abi_encoder/evm_data_types_test.ts  |  2 +-
 4 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 6bc299544..82a519aae 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -22,10 +22,6 @@ export class Bool extends PayloadDataType {
         }
     }
 
-    public getSignature(): string {
-        return 'bool';
-    }
-
     public encodeValue(value: boolean): Buffer {
         const encodedValue = value ? '0x1' : '0x0';
         const encodedValueBuf = ethUtil.setLengthLeft(
@@ -47,4 +43,8 @@ export class Bool extends PayloadDataType {
         /* tslint:enable boolean-naming */
         return value;
     }
+
+    public getSignature(): string {
+        return 'bool';
+    }
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index 626e266c9..ce6ace627 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -17,42 +17,53 @@ export class DynamicBytes extends PayloadDataType {
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         super(dataItem, dataTypeFactory, DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!DynamicBytes.matchType(dataItem.type)) {
-            throw new Error(`Tried to instantiate DynamicBytes with bad input: ${dataItem}`);
+            throw new Error(`Tried to instantiate Dynamic Bytes with bad input: ${dataItem}`);
         }
     }
 
     public encodeValue(value: string | Buffer): Buffer {
-        if (typeof value === 'string' && !value.startsWith('0x')) {
-            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '${value}'`);
-        }
+        // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
+        // 1/3 Construct the length
         const valueBuf = ethUtil.toBuffer(value);
-        if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-
-        const wordsForValue = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
-        const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedDynamicBytesForValue);
-        const paddedLengthBuf = ethUtil.setLengthLeft(
-            ethUtil.toBuffer(valueBuf.byteLength),
-            Constants.EVM_WORD_WIDTH_IN_BYTES,
-        );
-        const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
-        return encodedValueBuf;
+        const wordsToStoreValuePadded = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const bytesToStoreValuePadded = wordsToStoreValuePadded * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const lengthBuf = ethUtil.toBuffer(valueBuf.byteLength);
+        const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        // 2/3 Construct the value
+        this._sanityCheckValue(value);
+        const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
+        // 3/3 Combine length and value
+        const encodedValue = Buffer.concat([lengthBufPadded, valueBufPadded]);
+        return encodedValue;
     }
 
     public decodeValue(calldata: RawCalldata): string {
+        // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
+        // 1/2 Decode length
         const lengthBuf = calldata.popWord();
         const lengthHex = ethUtil.bufferToHex(lengthBuf);
         const length = parseInt(lengthHex, Constants.HEX_BASE);
-        const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const paddedValueBuf = calldata.popWords(wordsForValue);
-        const valueBuf = paddedValueBuf.slice(0, length);
-        const decodedValue = ethUtil.bufferToHex(valueBuf);
-        return decodedValue;
+        // 2/2 Decode value
+        const wordsToStoreValuePadded = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
+        const valueBuf = valueBufPadded.slice(0, length);
+        const value = ethUtil.bufferToHex(valueBuf);
+        this._sanityCheckValue(value);
+        return value;
     }
 
     public getSignature(): string {
         return 'bytes';
     }
+
+    private _sanityCheckValue(value: string | Buffer): void {
+        if (typeof value !== 'string') {
+            return;
+        }
+        if (!value.startsWith('0x')) {
+            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+    }
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 428ea21db..2bb6541a3 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -32,8 +32,8 @@ export class String extends PayloadDataType {
         const valueBuf = new Buffer(value);
         const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
         // 3/3 Combine length and value
-        const encodedValueBuf = Buffer.concat([lengthBufPadded, valueBufPadded]);
-        return encodedValueBuf;
+        const encodedValue = Buffer.concat([lengthBufPadded, valueBufPadded]);
+        return encodedValue;
     }
 
     public decodeValue(calldata: RawCalldata): string {
diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts
index 9c3e3c0f9..7cea86529 100644
--- a/packages/utils/test/abi_encoder/evm_data_types_test.ts
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -1018,7 +1018,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Encode Args and validate result
             expect(() => {
                 dataType.encode(args);
-            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
+            }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
         });
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
             // Create DataType object
-- 
cgit v1.2.3


From 22ce3e2e29fb50d9b9244c9ee567c124586be9ae Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 17:46:45 -0800
Subject: Comments for Array

---
 .../utils/src/abi_encoder/evm_data_types/array.ts  | 39 +++++++++++++---------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 527cdadfe..77e38ebd7 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -12,21 +12,26 @@ export class Array extends MemberDataType {
         return Array._MATCHER.test(type);
     }
 
-    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        // Sanity check
-        const matches = Array._MATCHER.exec(dataItem.type);
+    private static _decodeElementTypeAndLengthFromType(type: string): [string, undefined|number] {
+        const matches = Array._MATCHER.exec(type);
         if (matches === null || matches.length !== 3) {
-            throw new Error(`Could not parse array: ${dataItem.type}`);
+            throw new Error(`Could not parse array: ${type}`);
         } else if (matches[1] === undefined) {
-            throw new Error(`Could not parse array type: ${dataItem.type}`);
+            throw new Error(`Could not parse array type: ${type}`);
         } else if (matches[2] === undefined) {
-            throw new Error(`Could not parse array length: ${dataItem.type}`);
+            throw new Error(`Could not parse array length: ${type}`);
         }
-
-        const isArray = true;
         const arrayElementType = matches[1];
         const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], Constants.DEC_BASE);
+        return [arrayElementType, arrayLength];
+    }
+
+    public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+        // Construct parent
+        const isArray = true;
+        const [arrayElementType, arrayLength] = Array._decodeElementTypeAndLengthFromType(dataItem.type);
         super(dataItem, dataTypeFactory, isArray, arrayLength, arrayElementType);
+        // Set array properties
         this._elementType = arrayElementType;
         this._arraySignature = this._computeSignature();
     }
@@ -36,20 +41,22 @@ export class Array extends MemberDataType {
     }
 
     private _computeSignature(): string {
-        const dataItem: DataItem = {
+        // Compute signature for a single array element
+        const elementDataItem: DataItem = {
             type: this._elementType,
             name: 'N/A',
         };
-        const components = this.getDataItem().components;
-        if (components !== undefined) {
-            dataItem.components = components;
+        const elementComponents = this.getDataItem().components;
+        if (elementComponents !== undefined) {
+            elementDataItem.components = elementComponents;
         }
-        const elementDataType = this.getFactory().create(dataItem);
-        const type = elementDataType.getSignature();
+        const elementDataType = this.getFactory().create(elementDataItem);
+        const elementSignature = elementDataType.getSignature();
+        // Construct signature for array of type `element`
         if (this._arrayLength === undefined) {
-            return `${type}[]`;
+            return `${elementSignature}[]`;
         } else {
-            return `${type}[${this._arrayLength}]`;
+            return `${elementSignature}[${this._arrayLength}]`;
         }
     }
 }
-- 
cgit v1.2.3


From bb4d02e413119132f283ee17549cf5e1732d75b5 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 17:47:33 -0800
Subject: Comments for Address

---
 packages/utils/src/abi_encoder/evm_data_types/address.ts | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 9ae22bd9c..84f6665cb 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -34,17 +34,17 @@ export class Address extends PayloadDataType {
         if (!value.startsWith('0x')) {
             throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
         }
-        const valueAsBuffer = ethUtil.toBuffer(value);
-        if (valueAsBuffer.byteLength !== Address._ADDRESS_SIZE_IN_BYTES) {
+        const valueBuf = ethUtil.toBuffer(value);
+        if (valueBuf.byteLength !== Address._ADDRESS_SIZE_IN_BYTES) {
             throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
         }
-        const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const encodedValueBuf = ethUtil.setLengthLeft(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
         return encodedValueBuf;
     }
 
     public decodeValue(calldata: RawCalldata): string {
-        const paddedValueBuf = calldata.popWord();
-        const valueBuf = paddedValueBuf.slice(Address._DECODED_ADDRESS_OFFSET_IN_BYTES);
+        const valueBufPadded = calldata.popWord();
+        const valueBuf = valueBufPadded.slice(Address._DECODED_ADDRESS_OFFSET_IN_BYTES);
         const value = ethUtil.bufferToHex(valueBuf);
         return value;
     }
-- 
cgit v1.2.3


From 9a51af46ee4a35b3d1ce2fcdc6f561aa68307cf0 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 18:24:46 -0800
Subject: Payload -> Blob, Dependent -> Pointer, Member -> Set

---
 .../abstract_data_types/dependent_data_type.ts     |  51 -----
 .../src/abi_encoder/abstract_data_types/index.ts   |   5 +-
 .../abstract_data_types/member_data_type.ts        | 226 --------------------
 .../abstract_data_types/payload_data_type.ts       |  38 ----
 .../abi_encoder/abstract_data_types/types/blob.ts  |  38 ++++
 .../abi_encoder/abstract_data_types/types/index.ts |   3 +
 .../abstract_data_types/types/pointer.ts           |  51 +++++
 .../abi_encoder/abstract_data_types/types/set.ts   | 227 +++++++++++++++++++++
 .../utils/src/abi_encoder/calldata/blocks/blob.ts  |  20 ++
 .../utils/src/abi_encoder/calldata/blocks/index.ts |   3 +
 .../src/abi_encoder/calldata/blocks/pointer.ts     |  59 ++++++
 .../utils/src/abi_encoder/calldata/blocks/set.ts   |  47 +++++
 .../utils/src/abi_encoder/calldata/calldata.ts     |  14 +-
 .../src/abi_encoder/calldata/calldata_blocks.ts    |   3 -
 .../calldata/dependent_calldata_block.ts           |  59 ------
 packages/utils/src/abi_encoder/calldata/index.ts   |   7 +-
 .../abi_encoder/calldata/member_calldata_block.ts  |  48 -----
 .../abi_encoder/calldata/payload_calldata_block.ts |  20 --
 .../utils/src/abi_encoder/calldata/raw_calldata.ts |  25 ++-
 .../src/abi_encoder/evm_data_types/address.ts      |   4 +-
 .../utils/src/abi_encoder/evm_data_types/array.ts  |   4 +-
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |   4 +-
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    |   4 +-
 .../utils/src/abi_encoder/evm_data_types/int.ts    |  10 +-
 .../utils/src/abi_encoder/evm_data_types/method.ts |   4 +-
 .../src/abi_encoder/evm_data_types/pointer.ts      |   4 +-
 .../src/abi_encoder/evm_data_types/static_bytes.ts |   4 +-
 .../utils/src/abi_encoder/evm_data_types/string.ts |   4 +-
 .../utils/src/abi_encoder/evm_data_types/tuple.ts  |   4 +-
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |  16 +-
 30 files changed, 502 insertions(+), 504 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
 delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
 delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/index.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
 create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/blob.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/index.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
 create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/set.ts
 delete mode 100644 packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
 delete mode 100644 packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
 delete mode 100644 packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
 delete mode 100644 packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
deleted file mode 100644
index 7649b1836..000000000
--- a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { DataItem } from 'ethereum-types';
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-import { CalldataBlock, DependentCalldataBlock, RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
-import { DecodingRules } from '../utils/rules';
-
-import { DataType } from './data_type';
-import { DataTypeFactory } from './interfaces';
-
-export abstract class DependentDataType extends DataType {
-    protected _dependency: DataType;
-    protected _parent: DataType;
-    private readonly _isStatic: boolean;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
-        super(dataItem, factory);
-        this._dependency = dependency;
-        this._parent = parent;
-        this._isStatic = true;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
-        if (parentBlock === undefined) {
-            throw new Error(`DependentDataType requires a parent block to generate its block`);
-        }
-        const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock ? parentBlock.getName() : '';
-        const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const destinationOffsetBuf = calldata.popWord();
-        const destinationOffsetHex = ethUtil.bufferToHex(destinationOffsetBuf);
-        const destinationOffsetRelative = parseInt(destinationOffsetHex, Constants.HEX_BASE);
-        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
-        const currentOffset = calldata.getOffset();
-        calldata.setOffset(destinationOffsetAbsolute);
-        const value = this._dependency.generateValue(calldata, rules);
-        calldata.setOffset(currentOffset);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        return this._isStatic;
-    }
-}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/index.ts
index 9ad568134..d1c7d93e4 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/index.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/index.ts
@@ -1,5 +1,4 @@
 export * from './interfaces';
 export * from './data_type';
-export * from './dependent_data_type';
-export * from './member_data_type';
-export * from './payload_data_type';
+import * as AbstractDataTypes from './types';
+export { AbstractDataTypes };
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
deleted file mode 100644
index dacdbf8af..000000000
--- a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-import { DataItem } from 'ethereum-types';
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-import { BigNumber } from '../../configured_bignumber';
-import { CalldataBlock, MemberCalldataBlock, RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
-import { DecodingRules } from '../utils/rules';
-
-import { DataType } from './data_type';
-import { DependentDataType } from './dependent_data_type';
-import { DataTypeFactory, MemberIndexByName } from './interfaces';
-
-export abstract class MemberDataType extends DataType {
-    protected readonly _arrayLength: number | undefined;
-    protected readonly _arrayElementType: string | undefined;
-    private readonly _memberIndexByName: MemberIndexByName;
-    private readonly _members: DataType[];
-    private readonly _isArray: boolean;
-
-    public constructor(
-        dataItem: DataItem,
-        factory: DataTypeFactory,
-        isArray: boolean = false,
-        arrayLength?: number,
-        arrayElementType?: string,
-    ) {
-        super(dataItem, factory);
-        this._memberIndexByName = {};
-        this._members = [];
-        this._isArray = isArray;
-        this._arrayLength = arrayLength;
-        this._arrayElementType = arrayElementType;
-        if (isArray && arrayLength !== undefined) {
-            [this._members, this._memberIndexByName] = this._createMembersWithLength(dataItem, arrayLength);
-        } else if (!isArray) {
-            [this._members, this._memberIndexByName] = this._createMembersWithKeys(dataItem);
-        }
-    }
-
-    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const block =
-            value instanceof Array
-                ? this._generateCalldataBlockFromArray(value, parentBlock)
-                : this._generateCalldataBlockFromObject(value, parentBlock);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
-        let members = this._members;
-        if (this._isArray && this._arrayLength === undefined) {
-            const arrayLengthBuf = calldata.popWord();
-            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const hexBase = 16;
-            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
-            [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
-        }
-
-        calldata.startScope();
-        let value: any[] | object;
-        if (rules.structsAsObjects && !this._isArray) {
-            value = {};
-            _.each(this._memberIndexByName, (idx: number, key: string) => {
-                const member = this._members[idx];
-                const memberValue = member.generateValue(calldata, rules);
-                (value as { [key: string]: any })[key] = memberValue;
-            });
-        } else {
-            value = [];
-            _.each(members, (member: DataType, idx: number) => {
-                const memberValue = member.generateValue(calldata, rules);
-                (value as any[]).push(memberValue);
-            });
-        }
-        calldata.endScope();
-        return value;
-    }
-
-    public isStatic(): boolean {
-        /* For Tuple:
-                    const isStaticTuple = this.children.length === 0;
-                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
-           For Array:
-                if isLengthDefined = false then this is false
-
-                Otherwise if the first element is a Pointer then false
-        */
-
-        if (this._isArray && this._arrayLength === undefined) {
-            return false;
-        }
-
-        // Search for dependent members
-        const dependentMember = _.find(this._members, (member: DataType) => {
-            return member instanceof DependentDataType;
-        });
-        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
-        return isStatic;
-    }
-
-    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
-        // Sanity check length
-        if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
-            throw new Error(
-                `Expected array of ${JSON.stringify(
-                    this._arrayLength,
-                )} elements, but got array of length ${JSON.stringify(value.length)}`,
-            );
-        }
-
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
-            this.getDataItem().name,
-            this.getSignature(),
-            parentName,
-        );
-
-        let members = this._members;
-        if (this._isArray && this._arrayLength === undefined) {
-            [members] = this._createMembersWithLength(this.getDataItem(), value.length);
-
-            const lenBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
-                Constants.EVM_WORD_WIDTH_IN_BYTES,
-            );
-            methodBlock.setHeader(lenBuf);
-        }
-
-        const memberBlocks: CalldataBlock[] = [];
-        _.each(members, (member: DataType, idx: number) => {
-            const block = member.generateCalldataBlock(value[idx], methodBlock);
-            memberBlocks.push(block);
-        });
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
-            this.getDataItem().name,
-            this.getSignature(),
-            parentName,
-        );
-        const memberBlocks: CalldataBlock[] = [];
-        const childMap = _.cloneDeep(this._memberIndexByName);
-        _.forOwn(obj, (value: any, key: string) => {
-            if (!(key in childMap)) {
-                throw new Error(
-                    `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
-                );
-            }
-            const block = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, methodBlock);
-            memberBlocks.push(block);
-            delete childMap[key];
-        });
-
-        if (Object.keys(childMap).length !== 0) {
-            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
-        }
-
-        methodBlock.setMembers(memberBlocks);
-        return methodBlock;
-    }
-
-    protected _computeSignatureOfMembers(): string {
-        // Compute signature of members
-        let signature = `(`;
-        _.each(this._members, (member: DataType, i: number) => {
-            signature += member.getSignature();
-            if (i < this._members.length - 1) {
-                signature += ',';
-            }
-        });
-        signature += ')';
-        return signature;
-    }
-
-    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] {
-        // Sanity check
-        if (dataItem.components === undefined) {
-            throw new Error(`Expected components`);
-        }
-
-        const members: DataType[] = [];
-        const memberIndexByName: MemberIndexByName = {};
-        _.each(dataItem.components, (memberItem: DataItem) => {
-            const childDataItem: DataItem = {
-                type: memberItem.type,
-                name: `${dataItem.name}.${memberItem.name}`,
-            };
-            const components = memberItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberIndexByName[memberItem.name] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberIndexByName];
-    }
-
-    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] {
-        const members: DataType[] = [];
-        const memberIndexByName: MemberIndexByName = {};
-        const range = _.range(length);
-        _.each(range, (idx: number) => {
-            const childDataItem: DataItem = {
-                type: this._arrayElementType ? this._arrayElementType : '',
-                name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
-            };
-            const components = dataItem.components;
-            if (components !== undefined) {
-                childDataItem.components = components;
-            }
-            const child = this.getFactory().create(childDataItem, this);
-            memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length;
-            members.push(child);
-        });
-
-        return [members, memberIndexByName];
-    }
-}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
deleted file mode 100644
index fa420bc74..000000000
--- a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { DataItem } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { CalldataBlock, PayloadCalldataBlock, RawCalldata } from '../calldata';
-import { DecodingRules } from '../utils/rules';
-
-import { DataType } from './data_type';
-import { DataTypeFactory } from './interfaces';
-
-export abstract class PayloadDataType extends DataType {
-    protected _hasConstantSize: boolean;
-
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
-        super(dataItem, factory);
-        this._hasConstantSize = hasConstantSize;
-    }
-
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
-        const encodedValue = this.encodeValue(value);
-        const name = this.getDataItem().name;
-        const signature = this.getSignature();
-        const parentName = parentBlock ? parentBlock.getName() : '';
-        const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
-        return block;
-    }
-
-    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
-        const value = this.decodeValue(calldata);
-        return value;
-    }
-
-    public isStatic(): boolean {
-        return this._hasConstantSize;
-    }
-
-    public abstract encodeValue(value: any): Buffer;
-    public abstract decodeValue(calldata: RawCalldata): any;
-}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
new file mode 100644
index 000000000..f4246c893
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -0,0 +1,38 @@
+import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
+import { DecodingRules } from '../../utils/rules';
+
+import { DataType } from '../data_type';
+import { DataTypeFactory } from '../interfaces';
+
+export abstract class Blob extends DataType {
+    protected _hasConstantSize: boolean;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+        super(dataItem, factory);
+        this._hasConstantSize = hasConstantSize;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Blob {
+        const encodedValue = this.encodeValue(value);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock ? parentBlock.getName() : '';
+        const block = new CalldataBlocks.Blob(name, signature, parentName, encodedValue);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const value = this.decodeValue(calldata);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        return this._hasConstantSize;
+    }
+
+    public abstract encodeValue(value: any): Buffer;
+    public abstract decodeValue(calldata: RawCalldata): any;
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts
new file mode 100644
index 000000000..958582dae
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts
@@ -0,0 +1,3 @@
+export * from './blob';
+export * from './pointer';
+export * from './set';
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
new file mode 100644
index 000000000..47efac521
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -0,0 +1,51 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
+import * as Constants from '../../utils/constants';
+import { DecodingRules } from '../../utils/rules';
+
+import { DataType } from '../data_type';
+import { DataTypeFactory } from '../interfaces';
+
+export abstract class Pointer extends DataType {
+    protected _dependency: DataType;
+    protected _parent: DataType;
+    private readonly _isStatic: boolean;
+
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+        super(dataItem, factory);
+        this._dependency = dependency;
+        this._parent = parent;
+        this._isStatic = true;
+    }
+
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Pointer {
+        if (parentBlock === undefined) {
+            throw new Error(`DependentDataType requires a parent block to generate its block`);
+        }
+        const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
+        const name = this.getDataItem().name;
+        const signature = this.getSignature();
+        const parentName = parentBlock ? parentBlock.getName() : '';
+        const block = new CalldataBlocks.Pointer(name, signature, parentName, dependencyBlock, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
+        const destinationOffsetBuf = calldata.popWord();
+        const destinationOffsetHex = ethUtil.bufferToHex(destinationOffsetBuf);
+        const destinationOffsetRelative = parseInt(destinationOffsetHex, Constants.HEX_BASE);
+        const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
+        const currentOffset = calldata.getOffset();
+        calldata.setOffset(destinationOffsetAbsolute);
+        const value = this._dependency.generateValue(calldata, rules);
+        calldata.setOffset(currentOffset);
+        return value;
+    }
+
+    public isStatic(): boolean {
+        return this._isStatic;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
new file mode 100644
index 000000000..77fd7b3ea
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -0,0 +1,227 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../../../configured_bignumber';
+import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
+import * as Constants from '../../utils/constants';
+import { DecodingRules } from '../../utils/rules';
+
+import { DataType } from '../data_type';
+import { DataTypeFactory, MemberIndexByName } from '../interfaces';
+
+import { Pointer } from './pointer';
+
+export abstract class Set extends DataType {
+    protected readonly _arrayLength: number | undefined;
+    protected readonly _arrayElementType: string | undefined;
+    private readonly _memberIndexByName: MemberIndexByName;
+    private readonly _members: DataType[];
+    private readonly _isArray: boolean;
+
+    public constructor(
+        dataItem: DataItem,
+        factory: DataTypeFactory,
+        isArray: boolean = false,
+        arrayLength?: number,
+        arrayElementType?: string,
+    ) {
+        super(dataItem, factory);
+        this._memberIndexByName = {};
+        this._members = [];
+        this._isArray = isArray;
+        this._arrayLength = arrayLength;
+        this._arrayElementType = arrayElementType;
+        if (isArray && arrayLength !== undefined) {
+            [this._members, this._memberIndexByName] = this._createMembersWithLength(dataItem, arrayLength);
+        } else if (!isArray) {
+            [this._members, this._memberIndexByName] = this._createMembersWithKeys(dataItem);
+        }
+    }
+
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
+        const block =
+            value instanceof Array
+                ? this._generateCalldataBlockFromArray(value, parentBlock)
+                : this._generateCalldataBlockFromObject(value, parentBlock);
+        return block;
+    }
+
+    public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
+        let members = this._members;
+        if (this._isArray && this._arrayLength === undefined) {
+            const arrayLengthBuf = calldata.popWord();
+            const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+            const hexBase = 16;
+            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
+
+            [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+        }
+
+        calldata.startScope();
+        let value: any[] | object;
+        if (rules.structsAsObjects && !this._isArray) {
+            value = {};
+            _.each(this._memberIndexByName, (idx: number, key: string) => {
+                const member = this._members[idx];
+                const memberValue = member.generateValue(calldata, rules);
+                (value as { [key: string]: any })[key] = memberValue;
+            });
+        } else {
+            value = [];
+            _.each(members, (member: DataType, idx: number) => {
+                const memberValue = member.generateValue(calldata, rules);
+                (value as any[]).push(memberValue);
+            });
+        }
+        calldata.endScope();
+        return value;
+    }
+
+    public isStatic(): boolean {
+        /* For Tuple:
+                    const isStaticTuple = this.children.length === 0;
+                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
+
+           For Array:
+                if isLengthDefined = false then this is false
+
+                Otherwise if the first element is a Pointer then false
+        */
+
+        if (this._isArray && this._arrayLength === undefined) {
+            return false;
+        }
+
+        // Search for dependent members
+        const dependentMember = _.find(this._members, (member: DataType) => {
+            return member instanceof Pointer;
+        });
+        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
+        return isStatic;
+    }
+
+    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): CalldataBlocks.Set {
+        // Sanity check length
+        if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
+            throw new Error(
+                `Expected array of ${JSON.stringify(
+                    this._arrayLength,
+                )} elements, but got array of length ${JSON.stringify(value.length)}`,
+            );
+        }
+
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set(
+            this.getDataItem().name,
+            this.getSignature(),
+            parentName,
+        );
+
+        let members = this._members;
+        if (this._isArray && this._arrayLength === undefined) {
+            [members] = this._createMembersWithLength(this.getDataItem(), value.length);
+
+            const lenBuf = ethUtil.setLengthLeft(
+                ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
+                Constants.EVM_WORD_WIDTH_IN_BYTES,
+            );
+            methodBlock.setHeader(lenBuf);
+        }
+
+        const memberCalldataBlocks: CalldataBlock[] = [];
+        _.each(members, (member: DataType, idx: number) => {
+            const block = member.generateCalldataBlock(value[idx], methodBlock);
+            memberCalldataBlocks.push(block);
+        });
+        methodBlock.setMembers(memberCalldataBlocks);
+        return methodBlock;
+    }
+
+    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
+        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set(
+            this.getDataItem().name,
+            this.getSignature(),
+            parentName,
+        );
+        const memberCalldataBlocks: CalldataBlock[] = [];
+        const childMap = _.cloneDeep(this._memberIndexByName);
+        _.forOwn(obj, (value: any, key: string) => {
+            if (!(key in childMap)) {
+                throw new Error(
+                    `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
+                );
+            }
+            const block = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, methodBlock);
+            memberCalldataBlocks.push(block);
+            delete childMap[key];
+        });
+
+        if (Object.keys(childMap).length !== 0) {
+            throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
+        }
+
+        methodBlock.setMembers(memberCalldataBlocks);
+        return methodBlock;
+    }
+
+    protected _computeSignatureOfMembers(): string {
+        // Compute signature of members
+        let signature = `(`;
+        _.each(this._members, (member: DataType, i: number) => {
+            signature += member.getSignature();
+            if (i < this._members.length - 1) {
+                signature += ',';
+            }
+        });
+        signature += ')';
+        return signature;
+    }
+
+    private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] {
+        // Sanity check
+        if (dataItem.components === undefined) {
+            throw new Error(`Expected components`);
+        }
+
+        const members: DataType[] = [];
+        const memberIndexByName: MemberIndexByName = {};
+        _.each(dataItem.components, (memberItem: DataItem) => {
+            const childDataItem: DataItem = {
+                type: memberItem.type,
+                name: `${dataItem.name}.${memberItem.name}`,
+            };
+            const components = memberItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberIndexByName[memberItem.name] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberIndexByName];
+    }
+
+    private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] {
+        const members: DataType[] = [];
+        const memberIndexByName: MemberIndexByName = {};
+        const range = _.range(length);
+        _.each(range, (idx: number) => {
+            const childDataItem: DataItem = {
+                type: this._arrayElementType ? this._arrayElementType : '',
+                name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
+            };
+            const components = dataItem.components;
+            if (components !== undefined) {
+                childDataItem.components = components;
+            }
+            const child = this.getFactory().create(childDataItem, this);
+            memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length;
+            members.push(child);
+        });
+
+        return [members, memberIndexByName];
+    }
+}
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts
new file mode 100644
index 000000000..210ef6420
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts
@@ -0,0 +1,20 @@
+import { CalldataBlock } from '../calldata_block';
+
+export class Blob extends CalldataBlock {
+    private readonly _blob: Buffer;
+
+    constructor(name: string, signature: string, parentName: string, blob: Buffer) {
+        const headerSizeInBytes = 0;
+        const bodySizeInBytes = blob.byteLength;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
+        this._blob = blob;
+    }
+
+    public toBuffer(): Buffer {
+        return this._blob;
+    }
+
+    public getRawData(): Buffer {
+        return this._blob;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/index.ts b/packages/utils/src/abi_encoder/calldata/blocks/index.ts
new file mode 100644
index 000000000..958582dae
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/blocks/index.ts
@@ -0,0 +1,3 @@
+export * from './blob';
+export * from './pointer';
+export * from './set';
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
new file mode 100644
index 000000000..1c49a8c6c
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
@@ -0,0 +1,59 @@
+import * as ethUtil from 'ethereumjs-util';
+
+import * as Constants from '../../utils/constants';
+
+import { CalldataBlock } from '../calldata_block';
+
+export class Pointer extends CalldataBlock {
+    public static readonly RAW_DATA_START = new Buffer('<');
+    public static readonly RAW_DATA_END = new Buffer('>');
+    private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
+    private static readonly _EMPTY_HEADER_SIZE = 0;
+    private readonly _parent: CalldataBlock;
+    private readonly _dependency: CalldataBlock;
+    private _aliasFor: CalldataBlock | undefined;
+
+    constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) {
+        const headerSizeInBytes = Pointer._EMPTY_HEADER_SIZE;
+        const bodySizeInBytes = Pointer._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
+        this._parent = parent;
+        this._dependency = dependency;
+        this._aliasFor = undefined;
+    }
+
+    public toBuffer(): Buffer {
+        const destinationOffset =
+            this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
+        const parentOffset = this._parent.getOffsetInBytes();
+        const parentHeaderSize = this._parent.getHeaderSizeInBytes();
+        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
+        const pointerHex = `0x${pointer.toString(Constants.HEX_BASE)}`;
+        const pointerBuf = ethUtil.toBuffer(pointerHex);
+        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        return pointerBufPadded;
+    }
+
+    public getDependency(): CalldataBlock {
+        return this._dependency;
+    }
+
+    public setAlias(block: CalldataBlock): void {
+        this._aliasFor = block;
+        this._setName(`${this.getName()} (alias for ${block.getName()})`);
+    }
+
+    public getAlias(): CalldataBlock | undefined {
+        return this._aliasFor;
+    }
+
+    public getRawData(): Buffer {
+        const dependencyRawData = this._dependency.getRawData();
+        const rawDataComponents: Buffer[] = [];
+        rawDataComponents.push(Pointer.RAW_DATA_START);
+        rawDataComponents.push(dependencyRawData);
+        rawDataComponents.push(Pointer.RAW_DATA_END);
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts
new file mode 100644
index 000000000..e4de22c5c
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts
@@ -0,0 +1,47 @@
+import * as _ from 'lodash';
+
+import { CalldataBlock } from '../calldata_block';
+
+export class Set extends CalldataBlock {
+    private _header: Buffer | undefined;
+    private _members: CalldataBlock[];
+
+    constructor(name: string, signature: string, parentName: string) {
+        super(name, signature, parentName, 0, 0);
+        this._members = [];
+        this._header = undefined;
+    }
+
+    public getRawData(): Buffer {
+        const rawDataComponents: Buffer[] = [];
+        if (this._header) {
+            rawDataComponents.push(this._header);
+        }
+        _.each(this._members, (member: CalldataBlock) => {
+            const memberBuffer = member.getRawData();
+            rawDataComponents.push(memberBuffer);
+        });
+        const rawData = Buffer.concat(rawDataComponents);
+        return rawData;
+    }
+
+    public setMembers(members: CalldataBlock[]): void {
+        this._members = members;
+    }
+
+    public setHeader(header: Buffer): void {
+        this._setHeaderSize(header.byteLength);
+        this._header = header;
+    }
+
+    public toBuffer(): Buffer {
+        if (this._header) {
+            return this._header;
+        }
+        return new Buffer('');
+    }
+
+    public getMembers(): CalldataBlock[] {
+        return this._members;
+    }
+}
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 3b85f821b..b2396ee8f 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -5,8 +5,8 @@ import * as Constants from '../utils/constants';
 import { Queue } from '../utils/queue';
 import { EncodingRules } from '../utils/rules';
 
+import * as CalldataBlocks from './blocks';
 import { CalldataBlock } from './calldata_block';
-import * as CalldataBlocks from './calldata_blocks';
 
 export class Calldata {
     private readonly _rules: EncodingRules;
@@ -18,7 +18,7 @@ export class Calldata {
         const blockQueue = new Queue<CalldataBlock>();
 
         // Base Case
-        if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) {
+        if (!(block instanceof CalldataBlocks.Set)) {
             blockQueue.pushBack(block);
             return blockQueue;
         }
@@ -26,7 +26,7 @@ export class Calldata {
         // This is a Member Block
         const memberBlock = block;
         _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof CalldataBlocks.MemberCalldataBlock) {
+            if (member instanceof CalldataBlocks.Set) {
                 blockQueue.mergeFront(Calldata._createQueue(member));
             } else {
                 blockQueue.pushFront(member);
@@ -35,9 +35,9 @@ export class Calldata {
 
         // Children
         _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) {
+            if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) {
                 const dependency = member.getDependency();
-                if (dependency instanceof CalldataBlocks.MemberCalldataBlock) {
+                if (dependency instanceof CalldataBlocks.Set) {
                     blockQueue.mergeBack(Calldata._createQueue(dependency));
                 } else {
                     blockQueue.pushBack(dependency);
@@ -68,7 +68,7 @@ export class Calldata {
         const subtreeQueue = Calldata._createQueue(this._root);
         let block: CalldataBlock | undefined;
         for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) {
-            if (block instanceof CalldataBlocks.DependentCalldataBlock) {
+            if (block instanceof CalldataBlocks.Pointer) {
                 const dependencyBlockHashBuf = block.getDependency().computeHash();
                 const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
                 if (dependencyBlockHash in blocksByHash) {
@@ -175,7 +175,7 @@ export class Calldata {
                         ),
                     )
                     .padEnd(valuePadding);
-                if (block instanceof CalldataBlocks.MemberCalldataBlock) {
+                if (block instanceof CalldataBlocks.Set) {
                     nameStr = `### ${prettyName.padEnd(namePadding)}`;
                     line = `\n${offsetStr}${value}${nameStr}`;
                 } else {
diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
deleted file mode 100644
index 8d4e7d7ca..000000000
--- a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './dependent_calldata_block';
-export * from './member_calldata_block';
-export * from './payload_calldata_block';
diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
deleted file mode 100644
index 16b9a6fe6..000000000
--- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import * as ethUtil from 'ethereumjs-util';
-
-import * as Constants from '../utils/constants';
-
-import { CalldataBlock } from './calldata_block';
-
-export class DependentCalldataBlock extends CalldataBlock {
-    public static readonly RAW_DATA_START = new Buffer('<');
-    public static readonly RAW_DATA_END = new Buffer('>');
-    private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
-    private static readonly _EMPTY_HEADER_SIZE = 0;
-    private readonly _parent: CalldataBlock;
-    private readonly _dependency: CalldataBlock;
-    private _aliasFor: CalldataBlock | undefined;
-
-    constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) {
-        const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE;
-        const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
-        this._parent = parent;
-        this._dependency = dependency;
-        this._aliasFor = undefined;
-    }
-
-    public toBuffer(): Buffer {
-        const destinationOffset =
-            this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
-        const parentOffset = this._parent.getOffsetInBytes();
-        const parentHeaderSize = this._parent.getHeaderSizeInBytes();
-        const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
-        const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`);
-        const evmWordWidthInBytes = 32;
-        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes);
-        return pointerBufPadded;
-    }
-
-    public getDependency(): CalldataBlock {
-        return this._dependency;
-    }
-
-    public setAlias(block: CalldataBlock): void {
-        this._aliasFor = block;
-        this._setName(`${this.getName()} (alias for ${block.getName()})`);
-    }
-
-    public getAlias(): CalldataBlock | undefined {
-        return this._aliasFor;
-    }
-
-    public getRawData(): Buffer {
-        const dependencyRawData = this._dependency.getRawData();
-        const rawDataComponents: Buffer[] = [];
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START);
-        rawDataComponents.push(dependencyRawData);
-        rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END);
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-}
diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts
index 2c786cd8d..2ef75e8d0 100644
--- a/packages/utils/src/abi_encoder/calldata/index.ts
+++ b/packages/utils/src/abi_encoder/calldata/index.ts
@@ -1,6 +1,5 @@
-export * from './calldata_block';
-export * from './dependent_calldata_block';
-export * from './payload_calldata_block';
-export * from './member_calldata_block';
 export * from './calldata';
+export * from './calldata_block';
 export * from './raw_calldata';
+import * as CalldataBlocks from './blocks';
+export { CalldataBlocks };
diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
deleted file mode 100644
index c35beb8de..000000000
--- a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import * as _ from 'lodash';
-
-import { CalldataBlock } from './calldata_block';
-
-export class MemberCalldataBlock extends CalldataBlock {
-    private _header: Buffer | undefined;
-    private _members: CalldataBlock[];
-
-    constructor(name: string, signature: string, parentName: string) {
-        super(name, signature, parentName, 0, 0);
-        this._members = [];
-        this._header = undefined;
-    }
-
-    public getRawData(): Buffer {
-        const rawDataComponents: Buffer[] = [];
-        if (this._header !== undefined) {
-            rawDataComponents.push(this._header);
-        }
-        _.each(this._members, (member: CalldataBlock) => {
-            const memberBuffer = member.getRawData();
-            rawDataComponents.push(memberBuffer);
-        });
-
-        const rawData = Buffer.concat(rawDataComponents);
-        return rawData;
-    }
-
-    public setMembers(members: CalldataBlock[]): void {
-        this._members = members;
-    }
-
-    public setHeader(header: Buffer): void {
-        this._setHeaderSize(header.byteLength);
-        this._header = header;
-    }
-
-    public toBuffer(): Buffer {
-        if (this._header !== undefined) {
-            return this._header;
-        }
-        return new Buffer('');
-    }
-
-    public getMembers(): CalldataBlock[] {
-        return this._members;
-    }
-}
diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
deleted file mode 100644
index 0420b01d8..000000000
--- a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CalldataBlock } from './calldata_block';
-
-export class PayloadCalldataBlock extends CalldataBlock {
-    private readonly _payload: Buffer;
-
-    constructor(name: string, signature: string, parentName: string, payload: Buffer) {
-        const headerSizeInBytes = 0;
-        const bodySizeInBytes = payload.byteLength;
-        super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
-        this._payload = payload;
-    }
-
-    public toBuffer(): Buffer {
-        return this._payload;
-    }
-
-    public getRawData(): Buffer {
-        return this._payload;
-    }
-}
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index 9e72bbd62..b13cbdfd9 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -8,26 +8,25 @@ export class RawCalldata {
     private readonly _value: Buffer;
     private readonly _selector: string;
     private readonly _scopes: Queue<number>;
-    private _offset: number; // tracks current offset into raw calldata; used for parsing
+    private _offset: number;
 
-    constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) {
+    public constructor(value: string | Buffer, hasSelector: boolean = true) {
+        // Sanity check
         if (typeof value === 'string' && !value.startsWith('0x')) {
             throw new Error(`Expected raw calldata to start with '0x'`);
         }
-        const valueBuf = ethUtil.toBuffer(value);
-        if (hasSelectorPrefix) {
-            this._selector = ethUtil.bufferToHex(
-                valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES),
-            );
-            this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector
-        } else {
-            this._selector = '0x';
-            this._value = valueBuf;
-        }
-
+        // Construct initial values
+        this._value = ethUtil.toBuffer(value);
+        this._selector = '0x';
         this._scopes = new Queue<number>();
         this._scopes.pushBack(RawCalldata._INITIAL_OFFSET);
         this._offset = RawCalldata._INITIAL_OFFSET;
+        // If there's a selector then slice it
+        if (hasSelector) {
+            const selectorBuf = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES);
+            this._value = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES);
+            this._selector = ethUtil.bufferToHex(selectorBuf);
+        }
     }
 
     public popBytes(lengthInBytes: number): Buffer {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 84f6665cb..71aa293b5 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -3,11 +3,11 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 
-export class Address extends PayloadDataType {
+export class Address extends AbstractDataTypes.Blob {
     public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
     public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes';
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 77e38ebd7..54f7ba9fa 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -1,9 +1,9 @@
 import { DataItem } from 'ethereum-types';
 
-import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import * as Constants from '../utils/constants';
 
-export class Array extends MemberDataType {
+export class Array extends AbstractDataTypes.Set {
     private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$');
     private readonly _arraySignature: string;
     private readonly _elementType: string;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 82a519aae..031acc88a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -4,11 +4,11 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 
-export class Bool extends PayloadDataType {
+export class Bool extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index ce6ace627..01d83d11a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -3,11 +3,11 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 
-export class DynamicBytes extends PayloadDataType {
+export class DynamicBytes extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 83aeacd66..8a82ed4cc 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -2,21 +2,21 @@
 import { DataItem } from 'ethereum-types';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-export class Int extends PayloadDataType {
+export class Int extends AbstractDataTypes.Blob {
     private static readonly _MATCHER = RegExp(
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MAX_WIDTH: number = 256;
     private static readonly _DEFAULT_WIDTH: number = Int._MAX_WIDTH;
-    private _width: number;
-    private _minValue: BigNumber;
-    private _maxValue: BigNumber;
+    private readonly _width: number;
+    private readonly _minValue: BigNumber;
+    private readonly _maxValue: BigNumber;
 
     public static matchType(type: string): boolean {
         return Int._MATCHER.test(type);
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index f2e417485..bd4732097 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -2,13 +2,13 @@ import { DataItem, MethodAbi } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { DataType, DataTypeFactory, MemberDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types';
 import * as Constants from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { Tuple } from './tuple';
 
-export class Method extends MemberDataType {
+export class Method extends AbstractDataTypes.Set {
     private readonly _methodSignature: string;
     private readonly _methodSelector: string;
     private readonly _returnDataType: DataType;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
index d4411df9b..00c743d2b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -1,8 +1,8 @@
 import { DataItem } from 'ethereum-types';
 
-import { DataType, DataTypeFactory, DependentDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types';
 
-export class Pointer extends DependentDataType {
+export class Pointer extends AbstractDataTypes.Pointer {
     constructor(destDataType: DataType, parentDataType: DataType, dataTypeFactory: DataTypeFactory) {
         const destDataItem = destDataType.getDataItem();
         const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` };
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 0d01e6105..d0b41194e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -2,11 +2,11 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 
-export class StaticBytes extends PayloadDataType {
+export class StaticBytes extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MATCHER = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 2bb6541a3..6ab3513c9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -3,11 +3,11 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 
-export class String extends PayloadDataType {
+export class String extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 63d9dfa9e..3802f96c0 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -1,8 +1,8 @@
 import { DataItem } from 'ethereum-types';
 
-import { DataTypeFactory, MemberDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 
-export class Tuple extends MemberDataType {
+export class Tuple extends AbstractDataTypes.Set {
     private readonly _signature: string;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index 832ab075c..b1bc690d8 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -2,21 +2,21 @@
 import { DataItem } from 'ethereum-types';
 
 import { BigNumber } from '../../configured_bignumber';
-import { DataTypeFactory, PayloadDataType } from '../abstract_data_types';
+import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-export class UInt extends PayloadDataType {
+export class UInt extends AbstractDataTypes.Blob {
     private static readonly _MATCHER = RegExp(
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MAX_WIDTH: number = 256;
     private static readonly _DEFAULT_WIDTH: number = UInt._MAX_WIDTH;
-    private _width: number;
-    private _minValue: BigNumber;
-    private _maxValue: BigNumber;
+    private static readonly _MIN_VALUE = new BigNumber(0);
+    private readonly _width: number;
+    private readonly _maxValue: BigNumber;
 
     public static matchType(type: string): boolean {
         return UInt._MATCHER.test(type);
@@ -36,18 +36,17 @@ export class UInt extends PayloadDataType {
             throw new Error(`Tried to instantiate UInt with bad input: ${dataItem}`);
         }
         this._width = UInt._decodeWidthFromType(dataItem.type);
-        this._minValue = new BigNumber(0);
         this._maxValue = new BigNumber(2).toPower(this._width).sub(1);
     }
 
     public encodeValue(value: BigNumber | string | number): Buffer {
-        const encodedValue = EncoderMath.safeEncodeNumericValue(value, this._minValue, this._maxValue);
+        const encodedValue = EncoderMath.safeEncodeNumericValue(value, UInt._MIN_VALUE, this._maxValue);
         return encodedValue;
     }
 
     public decodeValue(calldata: RawCalldata): BigNumber {
         const valueBuf = calldata.popWord();
-        const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue);
+        const value = EncoderMath.safeDecodeNumericValue(valueBuf, UInt._MIN_VALUE, this._maxValue);
         return value;
     }
 
@@ -55,4 +54,3 @@ export class UInt extends PayloadDataType {
         return `uint${this._width}`;
     }
 }
-
-- 
cgit v1.2.3


From 8f73f53c95d8ba887558863b8b726a2b3f5b7e2b Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 20:05:41 -0800
Subject: Moved calldata iterator logic into its own iterator clas

---
 .../abi_encoder/abstract_data_types/types/blob.ts  |  8 +-
 .../abstract_data_types/types/pointer.ts           | 21 +++--
 .../utils/src/abi_encoder/calldata/calldata.ts     | 56 +++----------
 .../utils/src/abi_encoder/calldata/iterator.ts     | 94 ++++++++++++++++++++++
 .../src/abi_encoder/evm_data_types/pointer.ts      |  2 +-
 5 files changed, 119 insertions(+), 62 deletions(-)
 create mode 100644 packages/utils/src/abi_encoder/calldata/iterator.ts

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
index f4246c893..35ccc0586 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -8,11 +8,11 @@ import { DataType } from '../data_type';
 import { DataTypeFactory } from '../interfaces';
 
 export abstract class Blob extends DataType {
-    protected _hasConstantSize: boolean;
+    protected _sizeKnownAtCompileTime: boolean;
 
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, sizeKnownAtCompileTime: boolean) {
         super(dataItem, factory);
-        this._hasConstantSize = hasConstantSize;
+        this._sizeKnownAtCompileTime = sizeKnownAtCompileTime;
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Blob {
@@ -30,7 +30,7 @@ export abstract class Blob extends DataType {
     }
 
     public isStatic(): boolean {
-        return this._hasConstantSize;
+        return this._sizeKnownAtCompileTime;
     }
 
     public abstract encodeValue(value: any): Buffer;
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index 47efac521..46e60979a 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -1,3 +1,4 @@
+/* tslint:disable prefer-function-over-method  */
 import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
@@ -10,26 +11,24 @@ import { DataType } from '../data_type';
 import { DataTypeFactory } from '../interfaces';
 
 export abstract class Pointer extends DataType {
-    protected _dependency: DataType;
+    protected _destination: DataType;
     protected _parent: DataType;
-    private readonly _isStatic: boolean;
 
-    public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+    public constructor(dataItem: DataItem, factory: DataTypeFactory, destination: DataType, parent: DataType) {
         super(dataItem, factory);
-        this._dependency = dependency;
+        this._destination = destination;
         this._parent = parent;
-        this._isStatic = true;
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Pointer {
-        if (parentBlock === undefined) {
+        if (!parentBlock) {
             throw new Error(`DependentDataType requires a parent block to generate its block`);
         }
-        const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
+        const destinationBlock = this._destination.generateCalldataBlock(value, parentBlock);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
-        const parentName = parentBlock ? parentBlock.getName() : '';
-        const block = new CalldataBlocks.Pointer(name, signature, parentName, dependencyBlock, parentBlock);
+        const parentName = parentBlock.getName();
+        const block = new CalldataBlocks.Pointer(name, signature, parentName, destinationBlock, parentBlock);
         return block;
     }
 
@@ -40,12 +39,12 @@ export abstract class Pointer extends DataType {
         const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
         const currentOffset = calldata.getOffset();
         calldata.setOffset(destinationOffsetAbsolute);
-        const value = this._dependency.generateValue(calldata, rules);
+        const value = this._destination.generateValue(calldata, rules);
         calldata.setOffset(currentOffset);
         return value;
     }
 
     public isStatic(): boolean {
-        return this._isStatic;
+        return true;
     }
 }
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index b2396ee8f..dd9d47def 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -2,11 +2,11 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import * as Constants from '../utils/constants';
-import { Queue } from '../utils/queue';
 import { EncodingRules } from '../utils/rules';
 
 import * as CalldataBlocks from './blocks';
 import { CalldataBlock } from './calldata_block';
+import { CalldataIterator, ReverseCalldataIterator } from './iterator';
 
 export class Calldata {
     private readonly _rules: EncodingRules;
@@ -14,41 +14,6 @@ export class Calldata {
     private _sizeInBytes: number;
     private _root: CalldataBlock | undefined;
 
-    private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
-        const blockQueue = new Queue<CalldataBlock>();
-
-        // Base Case
-        if (!(block instanceof CalldataBlocks.Set)) {
-            blockQueue.pushBack(block);
-            return blockQueue;
-        }
-
-        // This is a Member Block
-        const memberBlock = block;
-        _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof CalldataBlocks.Set) {
-                blockQueue.mergeFront(Calldata._createQueue(member));
-            } else {
-                blockQueue.pushFront(member);
-            }
-        });
-
-        // Children
-        _.each(memberBlock.getMembers(), (member: CalldataBlock) => {
-            if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) {
-                const dependency = member.getDependency();
-                if (dependency instanceof CalldataBlocks.Set) {
-                    blockQueue.mergeBack(Calldata._createQueue(dependency));
-                } else {
-                    blockQueue.pushBack(dependency);
-                }
-            }
-        });
-
-        blockQueue.pushFront(memberBlock);
-        return blockQueue;
-    }
-
     public constructor(rules: EncodingRules) {
         this._rules = rules;
         this._selector = '';
@@ -65,9 +30,9 @@ export class Calldata {
 
         // 1. Create a queue of subtrees by hash
         // Note that they are ordered the same as
-        const subtreeQueue = Calldata._createQueue(this._root);
+        const iterator = new ReverseCalldataIterator(this._root);
         let block: CalldataBlock | undefined;
-        for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) {
+        while (block = iterator.next()) {
             if (block instanceof CalldataBlocks.Pointer) {
                 const dependencyBlockHashBuf = block.getDependency().computeHash();
                 const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
@@ -97,10 +62,10 @@ export class Calldata {
             this.optimize();
         }
 
-        const offsetQueue = Calldata._createQueue(this._root);
+        const iterator = new CalldataIterator(this._root);
         let block: CalldataBlock | undefined;
         let offset = 0;
-        for (block = offsetQueue.popFront(); block !== undefined; block = offsetQueue.popFront()) {
+        while (block = iterator.next()) {
             block.setOffset(offset);
             offset += block.getSizeInBytes();
         }
@@ -136,13 +101,12 @@ export class Calldata {
             throw new Error('expected root');
         }
 
-        const valueQueue = Calldata._createQueue(this._root);
+        const iterator = new CalldataIterator(this._root);
 
         let block: CalldataBlock | undefined;
         let offset = 0;
-        const functionBlock = valueQueue.peekFront();
-        const functionName: string = functionBlock === undefined ? '' : functionBlock.getName();
-        for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) {
+        const functionName: string = this._root.getName();
+        while (block = iterator.next()) {
             // Process each block 1 word at a time
             const size = block.getSizeInBytes();
             const name = block.getName();
@@ -209,10 +173,10 @@ export class Calldata {
             throw new Error('expected root');
         }
 
-        const valueQueue = Calldata._createQueue(this._root);
+        const iterator = new CalldataIterator(this._root);
         const valueBufs: Buffer[] = [selectorBuffer];
         let block: CalldataBlock | undefined;
-        for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) {
+        while (block = iterator.next()) {
             valueBufs.push(block.toBuffer());
         }
 
diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts
new file mode 100644
index 000000000..3e3367e10
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/iterator.ts
@@ -0,0 +1,94 @@
+/* tslint:disable max-classes-per-file */
+import * as _ from 'lodash';
+
+import { Queue } from '../utils/queue';
+
+import * as CalldataBlocks from './blocks';
+import { CalldataBlock } from './calldata_block';
+
+/**
+ * Iterator class for Calldata Blocks. Blocks follows the order
+ * they should be put into calldata that is passed to he EVM.
+ *
+ * Example #1:
+ * Let root = Set {
+ *                  Blob{} A,
+ *                  Pointer {
+ *                      Blob{} a
+ *                  } B,
+ *                  Blob{} C
+ *            }
+ * It will iterate as follows: [A, B, C, B.a]
+ *
+ * Example #2:
+ * Let root = Set {
+ *                  Blob{} A,
+ *                  Pointer {
+ *                      Blob{} a
+ *                      Pointer {
+ *                          Blob{} b
+ *                      }
+ *                  } B,
+ *                  Pointer {
+ *                      Blob{} c
+ *                  } C
+ *            }
+ * It will iterate as follows: [A, B, C, B.a, B.b, C.c]
+ */
+abstract class BaseIterator {
+    protected readonly _root: CalldataBlock;
+    protected readonly _queue: Queue<CalldataBlock>;
+
+    private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
+        const queue = new Queue<CalldataBlock>();
+        // Base case
+        if (!(block instanceof CalldataBlocks.Set)) {
+            queue.pushBack(block);
+            return queue;
+        }
+        // This is a set; add members
+        const set = block;
+        _.eachRight(set.getMembers(), (member: CalldataBlock) => {
+            queue.mergeFront(BaseIterator._createQueue(member));
+        });
+        // Add children
+        _.each(set.getMembers(), (member: CalldataBlock) => {
+            // Traverse child if it is a unique pointer.
+            // A pointer that is an alias for another pointer is ignored.
+            if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) {
+                const dependency = member.getDependency();
+                queue.mergeBack(BaseIterator._createQueue(dependency));
+            }
+        });
+        // Put set block at the front of the queue
+        queue.pushFront(set);
+        return queue;
+    }
+
+    public constructor(root: CalldataBlock) {
+        this._root = root;
+        this._queue = BaseIterator._createQueue(root);
+    }
+
+    public abstract next(): CalldataBlock | undefined;
+}
+
+export class CalldataIterator extends BaseIterator {
+    public constructor(root: CalldataBlock) {
+        super(root);
+    }
+
+    public next(): CalldataBlock | undefined {
+        return this._queue.popFront();
+    }
+}
+
+export class ReverseCalldataIterator extends BaseIterator {
+    public constructor(root: CalldataBlock) {
+        super(root);
+    }
+
+    public next(): CalldataBlock | undefined {
+        return this._queue.popBack();
+    }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
index 00c743d2b..e7c172afb 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -10,6 +10,6 @@ export class Pointer extends AbstractDataTypes.Pointer {
     }
 
     public getSignature(): string {
-        return this._dependency.getSignature();
+        return this._destination.getSignature();
     }
 }
-- 
cgit v1.2.3


From bab1c92c703ee53e77a56a7f7a5e3bba5b4a2306 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 20:11:10 -0800
Subject: Linter for Calldata Block Iterator

---
 .../utils/src/abi_encoder/calldata/calldata.ts     | 13 ++++-------
 .../utils/src/abi_encoder/calldata/iterator.ts     | 26 ++++++++++++++++++----
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index dd9d47def..50f0f0fad 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -31,8 +31,7 @@ export class Calldata {
         // 1. Create a queue of subtrees by hash
         // Note that they are ordered the same as
         const iterator = new ReverseCalldataIterator(this._root);
-        let block: CalldataBlock | undefined;
-        while (block = iterator.next()) {
+        for (const block of iterator) {
             if (block instanceof CalldataBlocks.Pointer) {
                 const dependencyBlockHashBuf = block.getDependency().computeHash();
                 const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
@@ -63,9 +62,8 @@ export class Calldata {
         }
 
         const iterator = new CalldataIterator(this._root);
-        let block: CalldataBlock | undefined;
         let offset = 0;
-        while (block = iterator.next()) {
+        for (const block of iterator) {
             block.setOffset(offset);
             offset += block.getSizeInBytes();
         }
@@ -102,11 +100,9 @@ export class Calldata {
         }
 
         const iterator = new CalldataIterator(this._root);
-
-        let block: CalldataBlock | undefined;
         let offset = 0;
         const functionName: string = this._root.getName();
-        while (block = iterator.next()) {
+        for (const block of iterator) {
             // Process each block 1 word at a time
             const size = block.getSizeInBytes();
             const name = block.getName();
@@ -175,8 +171,7 @@ export class Calldata {
 
         const iterator = new CalldataIterator(this._root);
         const valueBufs: Buffer[] = [selectorBuffer];
-        let block: CalldataBlock | undefined;
-        while (block = iterator.next()) {
+        for (const block of iterator) {
             valueBufs.push(block.toBuffer());
         }
 
diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts
index 3e3367e10..8e2b16a5a 100644
--- a/packages/utils/src/abi_encoder/calldata/iterator.ts
+++ b/packages/utils/src/abi_encoder/calldata/iterator.ts
@@ -35,7 +35,7 @@ import { CalldataBlock } from './calldata_block';
  *            }
  * It will iterate as follows: [A, B, C, B.a, B.b, C.c]
  */
-abstract class BaseIterator {
+abstract class BaseIterator implements Iterable<CalldataBlock> {
     protected readonly _root: CalldataBlock;
     protected readonly _queue: Queue<CalldataBlock>;
 
@@ -70,7 +70,25 @@ abstract class BaseIterator {
         this._queue = BaseIterator._createQueue(root);
     }
 
-    public abstract next(): CalldataBlock | undefined;
+    public [Symbol.iterator](): { next: () => IteratorResult<CalldataBlock> } {
+        return {
+            next: () => {
+                const nextBlock = this.nextBlock();
+                if (nextBlock !== undefined) {
+                    return {
+                        value: nextBlock,
+                        done: false,
+                    };
+                }
+                return {
+                    done: true,
+                    value: new CalldataBlocks.Blob('', '', '', new Buffer('')),
+                };
+            },
+        };
+    }
+
+    public abstract nextBlock(): CalldataBlock | undefined;
 }
 
 export class CalldataIterator extends BaseIterator {
@@ -78,7 +96,7 @@ export class CalldataIterator extends BaseIterator {
         super(root);
     }
 
-    public next(): CalldataBlock | undefined {
+    public nextBlock(): CalldataBlock | undefined {
         return this._queue.popFront();
     }
 }
@@ -88,7 +106,7 @@ export class ReverseCalldataIterator extends BaseIterator {
         super(root);
     }
 
-    public next(): CalldataBlock | undefined {
+    public nextBlock(): CalldataBlock | undefined {
         return this._queue.popBack();
     }
 }
-- 
cgit v1.2.3


From 50344fa24a4a708ae90030af107afb15366f883f Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 21:19:11 -0800
Subject: Added inline documentation for Calldata class

---
 .../abi_encoder/abstract_data_types/data_type.ts   |   4 +-
 .../utils/src/abi_encoder/calldata/calldata.ts     | 227 +++++++++++++--------
 2 files changed, 147 insertions(+), 84 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index 450080353..ab7df6ecc 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -32,8 +32,8 @@ export abstract class DataType {
         }
         const block = this.generateCalldataBlock(value);
         calldata.setRoot(block);
-        const calldataHex = calldata.toHexString();
-        return calldataHex;
+        const encodedCalldata = calldata.toString();
+        return encodedCalldata;
     }
 
     public decode(calldata: string, rules?: DecodingRules, selector?: string): any {
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 50f0f0fad..da61b2256 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -11,27 +11,107 @@ import { CalldataIterator, ReverseCalldataIterator } from './iterator';
 export class Calldata {
     private readonly _rules: EncodingRules;
     private _selector: string;
-    private _sizeInBytes: number;
     private _root: CalldataBlock | undefined;
 
     public constructor(rules: EncodingRules) {
         this._rules = rules;
         this._selector = '';
-        this._sizeInBytes = 0;
         this._root = undefined;
     }
-
-    public optimize(): void {
+    /**
+     * Sets the root calldata block. This block usually corresponds to a Method.
+     */
+    public setRoot(block: CalldataBlock): void {
+        this._root = block;
+    }
+    /**
+     * Sets the selector to be prepended onto the calldata.
+     * If the root block was created by a Method then a selector will likely be set.
+     */
+    public setSelector(selector: string): void {
+        if (!selector.startsWith('0x')) {
+            throw new Error(`Expected selector to be hex. Missing prefix '0x'`);
+        } else if (selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
+            throw new Error(`Invalid selector '${selector}'`);
+        }
+        this._selector = selector;
+    }
+    /**
+     * Iterates through the calldata blocks, starting from the root block, to construct calldata as a hex string.
+     * If the `optimize` flag is set then this calldata will be condensed, to save gas.
+     * If the `annotate` flag is set then this will return human-readable calldata.
+     * If the `annotate` flag is *not* set then this will return EVM-compatible calldata.
+     */
+    public toString(): string {
+        // Sanity check: root block must be set
+        if (this._root === undefined) {
+            throw new Error('expected root');
+        }
+        // Optimize, if flag set
+        if (this._rules.optimize) {
+            this._optimize();
+        }
+        // Set offsets
+        const iterator = new CalldataIterator(this._root);
+        let offset = 0;
+        for (const block of iterator) {
+            block.setOffset(offset);
+            offset += block.getSizeInBytes();
+        }
+        // Generate hex string
+        const hexString = this._rules.annotate ? this._toAnnotatedString() : this._toCondensedString();
+        return hexString;
+    }
+    /**
+     * There are three types of calldata blocks: Blob, Set and Pointer.
+     * Scenarios arise where distinct pointers resolve to identical values.
+     * We optimize by keeping only one such instance of the identical value, and redirecting all pointers here.
+     * We keep the last such duplicate value because pointers can only be positive (they cannot point backwards).
+     * 
+     * Example #1:
+     *  function f(string[], string[])
+     *  f(["foo", "bar", "blitz"], ["foo", "bar", "blitz"])
+     *  The array ["foo", "bar", "blitz"] will only be included in the calldata once.
+     * 
+     * Example #2:
+     *  function f(string[], string)
+     *  f(["foo", "bar", "blitz"], "foo")
+     *  The string "foo" will only be included in the calldata once.
+     * 
+     * Example #3:
+     *  function f((string, uint, bytes), string, uint, bytes)
+     *  f(("foo", 5, "0x05"), "foo", 5, "0x05")
+     *  The string "foo" and bytes "0x05" will only be included in the calldata once.
+     *  The duplicate `uint 5` values cannot be optimized out because they are static values (no pointer points to them).
+     * 
+     * @TODO #1:
+     *   This optimization strategy handles blocks that are exact duplicates of one another.
+     *   But what if some block is a combination of two other blocks? Or a subset of another block?
+     *   This optimization problem is not much different from the current implemetation.
+     *   Instead of tracking "observed" hashes, at each node we would simply do pattern-matching on the calldata.
+     *   This strategy would be applied after assigning offsets to the tree, rather than before (as in this strategy).
+     *   Note that one consequence of this strategy is pointers may resolve to offsets that are not word-aligned.
+     *   This shouldn't be a problem but further investigation should be done.
+     * 
+     * @TODO #2:
+     *   To be done as a follow-up to @TODO #1.
+     *   Since we optimize from the bottom-up, we could be affecting the outcome of a later potential optimization.
+     *   For example, what if by removing one duplicate value we miss out on optimizing another block higher in the tree. 
+     *   To handle this case, at each node we can store a candidate optimization in a priority queue (sorted by calldata size).
+     *   At the end of traversing the tree, the candidate at the front of the queue will be the most optimal output.
+     *   
+     */
+    private _optimize(): void {
+        // Step 1/1 Create a reverse iterator (starts from the end of the calldata to the beginning)
         if (this._root === undefined) {
             throw new Error('expected root');
         }
-
-        const blocksByHash: { [key: string]: CalldataBlock } = {};
-
-        // 1. Create a queue of subtrees by hash
-        // Note that they are ordered the same as
         const iterator = new ReverseCalldataIterator(this._root);
+        // Step 2/2 Iterate over each block, keeping track of which blocks have been seen and pruning redundant blocks.
+        const blocksByHash: { [key: string]: CalldataBlock } = {};
         for (const block of iterator) {
+            // If a block is a pointer and its value has already been observed, then update
+            // the pointer to resolve to the existing value.
             if (block instanceof CalldataBlocks.Pointer) {
                 const dependencyBlockHashBuf = block.getDependency().computeHash();
                 const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
@@ -43,7 +123,7 @@ export class Calldata {
                 }
                 continue;
             }
-
+            // This block has not been seen. Record its hash.
             const blockHashBuf = block.computeHash();
             const blockHash = ethUtil.bufferToHex(blockHashBuf);
             if (!(blockHash in blocksByHash)) {
@@ -51,84 +131,85 @@ export class Calldata {
             }
         }
     }
-
-    public toHexString(): string {
+    /**
+     * Returns EVM-compatible calldata as a Hex string.
+     */
+    private _toCondensedString(): string {
+        // Sanity check: must have a root block.
         if (this._root === undefined) {
             throw new Error('expected root');
         }
-
-        if (this._rules.optimize) {
-            this.optimize();
-        }
-
+        // Construct an array of buffers (one buffer for each block).
+        const selectorBuffer = ethUtil.toBuffer(this._selector);
+        const valueBufs: Buffer[] = [selectorBuffer];
         const iterator = new CalldataIterator(this._root);
-        let offset = 0;
         for (const block of iterator) {
-            block.setOffset(offset);
-            offset += block.getSizeInBytes();
+            valueBufs.push(block.toBuffer());
         }
-
-        const hexValue = this._rules.annotate ? this._generateAnnotatedHexString() : this._generateCondensedHexString();
+        // Create hex from buffer array.
+        const combinedBuffers = Buffer.concat(valueBufs);
+        const hexValue = ethUtil.bufferToHex(combinedBuffers);
         return hexValue;
     }
-
-    public getSelectorHex(): string {
-        return this._selector;
-    }
-
-    public getSizeInBytes(): number {
-        return this._sizeInBytes;
-    }
-
-    public setRoot(block: CalldataBlock): void {
-        this._root = block;
-        this._sizeInBytes += block.getSizeInBytes();
-    }
-
-    public setSelector(selector: string): void {
-        this._selector = selector.startsWith('0x') ? selector : `$0x${selector}`;
-        if (this._selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
-            throw new Error(`Invalid selector '${this._selector}'`);
-        }
-        this._sizeInBytes += Constants.HEX_SELECTOR_LENGTH_IN_BYTES; // @TODO: Used to be += 8. Bad?
-    }
-
-    private _generateAnnotatedHexString(): string {
-        let hexValue = `${this._selector}`;
+    /**
+     * Returns human-redable calldata.
+     * 
+     * Example:
+     *   simpleFunction(string[], string[])
+     *   strings = ["Hello", "World"]
+     *   simpleFunction(strings, strings)
+     * 
+     * Output:
+     *   0xbb4f12e3
+     *                                                                                      ### simpleFunction                                                                  
+     *   0x0       0000000000000000000000000000000000000000000000000000000000000040              ptr<array1> (alias for array2)                                                  
+     *   0x20      0000000000000000000000000000000000000000000000000000000000000040              ptr<array2>                                                                     
+     *
+     *   0x40      0000000000000000000000000000000000000000000000000000000000000002          ### array2                                                                          
+     *   0x60      0000000000000000000000000000000000000000000000000000000000000040              ptr<array2[0]>                                                                  
+     *   0x80      0000000000000000000000000000000000000000000000000000000000000080              ptr<array2[1]>                                                                  
+     *   0xa0      0000000000000000000000000000000000000000000000000000000000000005              array2[0]                                                                       
+     *   0xc0      48656c6c6f000000000000000000000000000000000000000000000000000000                                                                                          
+     *   0xe0      0000000000000000000000000000000000000000000000000000000000000005              array2[1]                                                                       
+     *   0x100     576f726c64000000000000000000000000000000000000000000000000000000     
+     */
+    private _toAnnotatedString(): string {
+        // Sanity check: must have a root block.
         if (this._root === undefined) {
             throw new Error('expected root');
         }
-
-        const iterator = new CalldataIterator(this._root);
+        // Construct annotated calldata
+        let hexValue = `${this._selector}`;
         let offset = 0;
         const functionName: string = this._root.getName();
+        const iterator = new CalldataIterator(this._root);
         for (const block of iterator) {
             // Process each block 1 word at a time
             const size = block.getSizeInBytes();
             const name = block.getName();
             const parentName = block.getParentName();
             const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');
-
-            // Current offset
-            let offsetStr = '';
-
-            // If this block is empty then it's a newline
             const offsetPadding = 10;
             const valuePadding = 74;
             const namePadding = 80;
             const evmWordStartIndex = 0;
             const emptySize = 0;
-            let value = '';
+            // Resulting line will be <offsetStr><valueStr><nameStr>
+            let offsetStr = '';
+            let valueStr = '';
             let nameStr = '';
-            let line = '';
+            let lineStr = '';
             if (size === emptySize) {
+                // This is a Set block with no header.
+                // For example, a tuple or an array with a defined length.
                 offsetStr = ' '.repeat(offsetPadding);
-                value = ' '.repeat(valuePadding);
+                valueStr = ' '.repeat(valuePadding);
                 nameStr = `### ${prettyName.padEnd(namePadding)}`;
-                line = `\n${offsetStr}${value}${nameStr}`;
+                lineStr = `\n${offsetStr}${valueStr}${nameStr}`;
             } else {
+                // This block has at least one word of value.
                 offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
-                value = ethUtil
+                valueStr = ethUtil
                     .stripHexPrefix(
                         ethUtil.bufferToHex(
                             block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES),
@@ -137,46 +218,28 @@ export class Calldata {
                     .padEnd(valuePadding);
                 if (block instanceof CalldataBlocks.Set) {
                     nameStr = `### ${prettyName.padEnd(namePadding)}`;
-                    line = `\n${offsetStr}${value}${nameStr}`;
+                    lineStr = `\n${offsetStr}${valueStr}${nameStr}`;
                 } else {
                     nameStr = `    ${prettyName.padEnd(namePadding)}`;
-                    line = `${offsetStr}${value}${nameStr}`;
+                    lineStr = `${offsetStr}${valueStr}${nameStr}`;
                 }
             }
-
+            // This block has a value that is more than 1 word.
             for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) {
                 offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
-                value = ethUtil
+                valueStr = ethUtil
                     .stripHexPrefix(
                         ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)),
                     )
                     .padEnd(valuePadding);
                 nameStr = ' '.repeat(namePadding);
-                line = `${line}\n${offsetStr}${value}${nameStr}`;
+                lineStr = `${lineStr}\n${offsetStr}${valueStr}${nameStr}`;
             }
-
             // Append to hex value
-            hexValue = `${hexValue}\n${line}`;
+            hexValue = `${hexValue}\n${lineStr}`;
             offset += size;
         }
 
         return hexValue;
     }
-
-    private _generateCondensedHexString(): string {
-        const selectorBuffer = ethUtil.toBuffer(this._selector);
-        if (this._root === undefined) {
-            throw new Error('expected root');
-        }
-
-        const iterator = new CalldataIterator(this._root);
-        const valueBufs: Buffer[] = [selectorBuffer];
-        for (const block of iterator) {
-            valueBufs.push(block.toBuffer());
-        }
-
-        const combinedBuffers = Buffer.concat(valueBufs);
-        const hexValue = ethUtil.bufferToHex(combinedBuffers);
-        return hexValue;
-    }
 }
-- 
cgit v1.2.3


From 3bf5a4e83f57f82090a64fc76fcc7bf3f7c68607 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 21:20:46 -0800
Subject: Moved some consts outside of a loop

---
 packages/utils/src/abi_encoder/calldata/calldata.ts | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index da61b2256..668b92f06 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -178,6 +178,12 @@ export class Calldata {
         if (this._root === undefined) {
             throw new Error('expected root');
         }
+        // Constants for constructing annotated string
+        const offsetPadding = 10;
+        const valuePadding = 74;
+        const namePadding = 80;
+        const evmWordStartIndex = 0;
+        const emptySize = 0;
         // Construct annotated calldata
         let hexValue = `${this._selector}`;
         let offset = 0;
@@ -189,11 +195,6 @@ export class Calldata {
             const name = block.getName();
             const parentName = block.getParentName();
             const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, '');
-            const offsetPadding = 10;
-            const valuePadding = 74;
-            const namePadding = 80;
-            const evmWordStartIndex = 0;
-            const emptySize = 0;
             // Resulting line will be <offsetStr><valueStr><nameStr>
             let offsetStr = '';
             let valueStr = '';
-- 
cgit v1.2.3


From a8d707b4627b8997b02c53e670bd1f5636eced4c Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 21:23:37 -0800
Subject: Linter on Calldata

---
 .../utils/src/abi_encoder/calldata/calldata.ts     | 39 +++++++++++-----------
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 668b92f06..a662f30b9 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -67,23 +67,23 @@ export class Calldata {
      * Scenarios arise where distinct pointers resolve to identical values.
      * We optimize by keeping only one such instance of the identical value, and redirecting all pointers here.
      * We keep the last such duplicate value because pointers can only be positive (they cannot point backwards).
-     * 
+     *
      * Example #1:
      *  function f(string[], string[])
      *  f(["foo", "bar", "blitz"], ["foo", "bar", "blitz"])
      *  The array ["foo", "bar", "blitz"] will only be included in the calldata once.
-     * 
+     *
      * Example #2:
      *  function f(string[], string)
      *  f(["foo", "bar", "blitz"], "foo")
      *  The string "foo" will only be included in the calldata once.
-     * 
+     *
      * Example #3:
      *  function f((string, uint, bytes), string, uint, bytes)
      *  f(("foo", 5, "0x05"), "foo", 5, "0x05")
      *  The string "foo" and bytes "0x05" will only be included in the calldata once.
      *  The duplicate `uint 5` values cannot be optimized out because they are static values (no pointer points to them).
-     * 
+     *
      * @TODO #1:
      *   This optimization strategy handles blocks that are exact duplicates of one another.
      *   But what if some block is a combination of two other blocks? Or a subset of another block?
@@ -92,14 +92,14 @@ export class Calldata {
      *   This strategy would be applied after assigning offsets to the tree, rather than before (as in this strategy).
      *   Note that one consequence of this strategy is pointers may resolve to offsets that are not word-aligned.
      *   This shouldn't be a problem but further investigation should be done.
-     * 
+     *
      * @TODO #2:
      *   To be done as a follow-up to @TODO #1.
      *   Since we optimize from the bottom-up, we could be affecting the outcome of a later potential optimization.
-     *   For example, what if by removing one duplicate value we miss out on optimizing another block higher in the tree. 
+     *   For example, what if by removing one duplicate value we miss out on optimizing another block higher in the tree.
      *   To handle this case, at each node we can store a candidate optimization in a priority queue (sorted by calldata size).
      *   At the end of traversing the tree, the candidate at the front of the queue will be the most optimal output.
-     *   
+     *
      */
     private _optimize(): void {
         // Step 1/1 Create a reverse iterator (starts from the end of the calldata to the beginning)
@@ -153,25 +153,25 @@ export class Calldata {
     }
     /**
      * Returns human-redable calldata.
-     * 
+     *
      * Example:
      *   simpleFunction(string[], string[])
      *   strings = ["Hello", "World"]
      *   simpleFunction(strings, strings)
-     * 
+     *
      * Output:
      *   0xbb4f12e3
-     *                                                                                      ### simpleFunction                                                                  
-     *   0x0       0000000000000000000000000000000000000000000000000000000000000040              ptr<array1> (alias for array2)                                                  
-     *   0x20      0000000000000000000000000000000000000000000000000000000000000040              ptr<array2>                                                                     
+     *                                                                                      ### simpleFunction
+     *   0x0       0000000000000000000000000000000000000000000000000000000000000040              ptr<array1> (alias for array2)
+     *   0x20      0000000000000000000000000000000000000000000000000000000000000040              ptr<array2>
      *
-     *   0x40      0000000000000000000000000000000000000000000000000000000000000002          ### array2                                                                          
-     *   0x60      0000000000000000000000000000000000000000000000000000000000000040              ptr<array2[0]>                                                                  
-     *   0x80      0000000000000000000000000000000000000000000000000000000000000080              ptr<array2[1]>                                                                  
-     *   0xa0      0000000000000000000000000000000000000000000000000000000000000005              array2[0]                                                                       
-     *   0xc0      48656c6c6f000000000000000000000000000000000000000000000000000000                                                                                          
-     *   0xe0      0000000000000000000000000000000000000000000000000000000000000005              array2[1]                                                                       
-     *   0x100     576f726c64000000000000000000000000000000000000000000000000000000     
+     *   0x40      0000000000000000000000000000000000000000000000000000000000000002          ### array2
+     *   0x60      0000000000000000000000000000000000000000000000000000000000000040              ptr<array2[0]>
+     *   0x80      0000000000000000000000000000000000000000000000000000000000000080              ptr<array2[1]>
+     *   0xa0      0000000000000000000000000000000000000000000000000000000000000005              array2[0]
+     *   0xc0      48656c6c6f000000000000000000000000000000000000000000000000000000
+     *   0xe0      0000000000000000000000000000000000000000000000000000000000000005              array2[1]
+     *   0x100     576f726c64000000000000000000000000000000000000000000000000000000
      */
     private _toAnnotatedString(): string {
         // Sanity check: must have a root block.
@@ -240,7 +240,6 @@ export class Calldata {
             hexValue = `${hexValue}\n${lineStr}`;
             offset += size;
         }
-
         return hexValue;
     }
 }
-- 
cgit v1.2.3


From feb551a02efe144b0aca4696f01dcdd42383fb36 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 21:39:47 -0800
Subject: Comments to Set datatype

---
 .../abi_encoder/abstract_data_types/types/set.ts   | 77 ++++++++++------------
 1 file changed, 35 insertions(+), 42 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 77fd7b3ea..427122ad6 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -49,18 +49,19 @@ export abstract class Set extends DataType {
 
     public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
         let members = this._members;
+        // Case 1: This is an array of undefined length, which means that `this._members` was not
+        //         populated in the constructor. So, construct the set of members it now.
         if (this._isArray && this._arrayLength === undefined) {
             const arrayLengthBuf = calldata.popWord();
             const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const hexBase = 16;
-            const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
+            const arrayLength = new BigNumber(arrayLengthHex, Constants.HEX_BASE);
             [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
         }
-
+        // Create a new scope in the calldata, before descending into the members of this set.
         calldata.startScope();
         let value: any[] | object;
         if (rules.structsAsObjects && !this._isArray) {
+            // Construct an object with values for each member of the set.
             value = {};
             _.each(this._memberIndexByName, (idx: number, key: string) => {
                 const member = this._members[idx];
@@ -68,41 +69,33 @@ export abstract class Set extends DataType {
                 (value as { [key: string]: any })[key] = memberValue;
             });
         } else {
+            // Construct an array with values for each member of the set.
             value = [];
             _.each(members, (member: DataType, idx: number) => {
                 const memberValue = member.generateValue(calldata, rules);
                 (value as any[]).push(memberValue);
             });
         }
+        // Close this scope and return tetheh value.
         calldata.endScope();
         return value;
     }
 
     public isStatic(): boolean {
-        /* For Tuple:
-                    const isStaticTuple = this.children.length === 0;
-                    return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
-           For Array:
-                if isLengthDefined = false then this is false
-
-                Otherwise if the first element is a Pointer then false
-        */
-
+        // An array with an undefined length is never static.
         if (this._isArray && this._arrayLength === undefined) {
             return false;
         }
-
-        // Search for dependent members
+        // If any member of the set is a pointer then the set is not static.
         const dependentMember = _.find(this._members, (member: DataType) => {
             return member instanceof Pointer;
         });
-        const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
+        const isStatic = dependentMember === undefined;
         return isStatic;
     }
 
     protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): CalldataBlocks.Set {
-        // Sanity check length
+        // Sanity check: if the set has a defined length then `value` must have the same length.
         if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
             throw new Error(
                 `Expected array of ${JSON.stringify(
@@ -110,41 +103,42 @@ export abstract class Set extends DataType {
                 )} elements, but got array of length ${JSON.stringify(value.length)}`,
             );
         }
-
+        // Create a new calldata block for this set.
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set(
+        const block: CalldataBlocks.Set = new CalldataBlocks.Set(
             this.getDataItem().name,
             this.getSignature(),
             parentName,
         );
-
+        // If this set has an undefined length then set its header to be the number of elements.
         let members = this._members;
         if (this._isArray && this._arrayLength === undefined) {
             [members] = this._createMembersWithLength(this.getDataItem(), value.length);
-
             const lenBuf = ethUtil.setLengthLeft(
                 ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
                 Constants.EVM_WORD_WIDTH_IN_BYTES,
             );
-            methodBlock.setHeader(lenBuf);
+            block.setHeader(lenBuf);
         }
-
+        // Create blocks for members of set.
         const memberCalldataBlocks: CalldataBlock[] = [];
         _.each(members, (member: DataType, idx: number) => {
-            const block = member.generateCalldataBlock(value[idx], methodBlock);
-            memberCalldataBlocks.push(block);
+            const memberBlock = member.generateCalldataBlock(value[idx], block);
+            memberCalldataBlocks.push(memberBlock);
         });
-        methodBlock.setMembers(memberCalldataBlocks);
-        return methodBlock;
+        block.setMembers(memberCalldataBlocks);
+        return block;
     }
 
     protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
+        // Create a new calldata block for this set.
         const parentName = parentBlock === undefined ? '' : parentBlock.getName();
-        const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set(
+        const block: CalldataBlocks.Set = new CalldataBlocks.Set(
             this.getDataItem().name,
             this.getSignature(),
             parentName,
         );
+        // Create blocks for members of set.
         const memberCalldataBlocks: CalldataBlock[] = [];
         const childMap = _.cloneDeep(this._memberIndexByName);
         _.forOwn(obj, (value: any, key: string) => {
@@ -153,17 +147,17 @@ export abstract class Set extends DataType {
                     `Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
                 );
             }
-            const block = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, methodBlock);
-            memberCalldataBlocks.push(block);
+            const memberBlock = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, block);
+            memberCalldataBlocks.push(memberBlock);
             delete childMap[key];
         });
-
+        // Sanity check that all members have been included.
         if (Object.keys(childMap).length !== 0) {
             throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
         }
-
-        methodBlock.setMembers(memberCalldataBlocks);
-        return methodBlock;
+        // Associate member blocks with Set block.
+        block.setMembers(memberCalldataBlocks);
+        return block;
     }
 
     protected _computeSignatureOfMembers(): string {
@@ -184,7 +178,7 @@ export abstract class Set extends DataType {
         if (dataItem.components === undefined) {
             throw new Error(`Expected components`);
         }
-
+        // Create one member for each component of `dataItem`
         const members: DataType[] = [];
         const memberIndexByName: MemberIndexByName = {};
         _.each(dataItem.components, (memberItem: DataItem) => {
@@ -200,28 +194,27 @@ export abstract class Set extends DataType {
             memberIndexByName[memberItem.name] = members.length;
             members.push(child);
         });
-
         return [members, memberIndexByName];
     }
 
     private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] {
+        // Create `length` members, deriving the type from `dataItem`
         const members: DataType[] = [];
         const memberIndexByName: MemberIndexByName = {};
         const range = _.range(length);
         _.each(range, (idx: number) => {
-            const childDataItem: DataItem = {
+            const memberDataItem: DataItem = {
                 type: this._arrayElementType ? this._arrayElementType : '',
                 name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
             };
             const components = dataItem.components;
             if (components !== undefined) {
-                childDataItem.components = components;
+                memberDataItem.components = components;
             }
-            const child = this.getFactory().create(childDataItem, this);
+            const memberType = this.getFactory().create(memberDataItem, this);
             memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length;
-            members.push(child);
+            members.push(memberType);
         });
-
         return [members, memberIndexByName];
     }
 }
-- 
cgit v1.2.3


From ad1b5af4e59ba750c019cab1f5ec9584b8645101 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Sun, 25 Nov 2018 21:40:37 -0800
Subject: Ran prettier

---
 packages/utils/src/abi_encoder/evm_data_types/array.ts       |  2 +-
 packages/utils/src/abi_encoder/evm_data_types/int.ts         |  7 ++++---
 .../utils/src/abi_encoder/evm_data_types/static_bytes.ts     |  7 ++++---
 packages/utils/src/abi_encoder/evm_data_types/uint.ts        |  7 ++++---
 packages/utils/src/abi_encoder/utils/math.ts                 | 12 ++++++++++--
 5 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 54f7ba9fa..8cf2cf7cf 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -12,7 +12,7 @@ export class Array extends AbstractDataTypes.Set {
         return Array._MATCHER.test(type);
     }
 
-    private static _decodeElementTypeAndLengthFromType(type: string): [string, undefined|number] {
+    private static _decodeElementTypeAndLengthFromType(type: string): [string, undefined | number] {
         const matches = Array._MATCHER.exec(type);
         if (matches === null || matches.length !== 3) {
             throw new Error(`Could not parse array: ${type}`);
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 8a82ed4cc..032cd045a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -24,9 +24,10 @@ export class Int extends AbstractDataTypes.Blob {
 
     private static _decodeWidthFromType(type: string): number {
         const matches = Int._MATCHER.exec(type);
-        const width = (matches !== null && matches.length === 2 && matches[1] !== undefined)
-        ? parseInt(matches[1], Constants.DEC_BASE)
-        : Int._DEFAULT_WIDTH;
+        const width =
+            matches !== null && matches.length === 2 && matches[1] !== undefined
+                ? parseInt(matches[1], Constants.DEC_BASE)
+                : Int._DEFAULT_WIDTH;
         return width;
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index d0b41194e..2c649cb33 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -20,9 +20,10 @@ export class StaticBytes extends AbstractDataTypes.Blob {
 
     private static _decodeWidthFromType(type: string): number {
         const matches = StaticBytes._MATCHER.exec(type);
-        const width = (matches !== null && matches.length === 3 && matches[2] !== undefined)
-            ? parseInt(matches[2], Constants.DEC_BASE)
-            : StaticBytes._DEFAULT_WIDTH;
+        const width =
+            matches !== null && matches.length === 3 && matches[2] !== undefined
+                ? parseInt(matches[2], Constants.DEC_BASE)
+                : StaticBytes._DEFAULT_WIDTH;
         return width;
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index b1bc690d8..b5b7683a2 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -24,9 +24,10 @@ export class UInt extends AbstractDataTypes.Blob {
 
     private static _decodeWidthFromType(type: string): number {
         const matches = UInt._MATCHER.exec(type);
-        const width = (matches !== null && matches.length === 2 && matches[1] !== undefined)
-        ? parseInt(matches[1], Constants.DEC_BASE)
-        : UInt._DEFAULT_WIDTH;
+        const width =
+            matches !== null && matches.length === 2 && matches[1] !== undefined
+                ? parseInt(matches[1], Constants.DEC_BASE)
+                : UInt._DEFAULT_WIDTH;
         return width;
     }
 
diff --git a/packages/utils/src/abi_encoder/utils/math.ts b/packages/utils/src/abi_encoder/utils/math.ts
index 8d21ada0a..c5fa10e73 100644
--- a/packages/utils/src/abi_encoder/utils/math.ts
+++ b/packages/utils/src/abi_encoder/utils/math.ts
@@ -4,7 +4,11 @@ import * as _ from 'lodash';
 
 import * as Constants from '../utils/constants';
 
-function sanityCheckBigNumberRange(value_: BigNumber | string | number, minValue: BigNumber, maxValue: BigNumber): void {
+function sanityCheckBigNumberRange(
+    value_: BigNumber | string | number,
+    minValue: BigNumber,
+    maxValue: BigNumber,
+): void {
     const value = new BigNumber(value_, 10);
     if (value.greaterThan(maxValue)) {
         throw new Error(`Tried to assign value of ${value}, which exceeds max value of ${maxValue}`);
@@ -51,7 +55,11 @@ export function encodeNumericValue(value_: BigNumber | string | number): Buffer
  * @param value_    The value to encode.
  * @return ABI Encoded value
  */
-export function safeEncodeNumericValue(value: BigNumber | string | number, minValue: BigNumber, maxValue: BigNumber): Buffer {
+export function safeEncodeNumericValue(
+    value: BigNumber | string | number,
+    minValue: BigNumber,
+    maxValue: BigNumber,
+): Buffer {
     sanityCheckBigNumberRange(value, minValue, maxValue);
     const encodedValue = encodeNumericValue(value);
     return encodedValue;
-- 
cgit v1.2.3


From 2e79ce26cbeacdeb0ea52b7c2e3da68e8055e7c6 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Mon, 26 Nov 2018 18:00:05 -0800
Subject: Tests use to.be.deep.equal instead of JSON

---
 .../utils/test/abi_encoder/evm_data_types_test.ts  | 176 ++++++---------------
 packages/utils/test/abi_encoder/methods_test.ts    |  72 +++------
 packages/utils/test/abi_encoder/optimizer_test.ts  |  64 ++------
 .../utils/test/abi_encoder/return_values_test.ts   |  24 +--
 4 files changed, 84 insertions(+), 252 deletions(-)

diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts
index 7cea86529..b99500265 100644
--- a/packages/utils/test/abi_encoder/evm_data_types_test.ts
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -24,9 +24,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Dynamic size; Static elements', async () => {
             // Create DataType object
@@ -41,9 +39,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Fixed size; Dynamic elements', async () => {
             // Create DataType object
@@ -58,9 +54,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Dynamic size; Dynamic elements', async () => {
             // Create DataType object
@@ -75,9 +69,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Dynamic Size; Multidimensional; Dynamic Elements', async () => {
             // Create DataType object
@@ -95,9 +87,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Dynamic Size; Multidimensional; Static Elements', async () => {
             // Create DataType object
@@ -115,9 +105,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Static Size; Multidimensional; Static Elements', async () => {
             // Create DataType object
@@ -134,9 +122,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Static Size; Multidimensional; Dynamic Elements', async () => {
             // Create DataType object
@@ -153,9 +139,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Static size; Too Few Elements', async () => {
             // Create DataType object
@@ -211,9 +195,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Dynamic elements only', async () => {
             // Create DataType object
@@ -233,9 +215,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Nested Static Array', async () => {
             // Create DataType object
@@ -255,9 +235,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Nested Dynamic Array', async () => {
             // Create DataType object
@@ -277,9 +255,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Nested Static Multidimensional Array', async () => {
             // Create DataType object
@@ -301,9 +277,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Nested Dynamic Multidimensional Array', async () => {
             // Create DataType object
@@ -325,9 +299,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Static and dynamic elements mixed', async () => {
             // Create DataType object
@@ -357,9 +329,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Decode Encoded Args and validate result
             const decodingRules: AbiEncoder.DecodingRules = { structsAsObjects: true };
             const decodedArgs = dataType.decode(encodedArgs, decodingRules);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Missing Key', async () => {
             // Create DataType object
@@ -406,9 +376,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Invalid Address - input is not valid hex', async () => {
             // Create DataType object
@@ -447,9 +415,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('False', async () => {
             // Create DataType object
@@ -463,9 +429,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
     });
 
@@ -489,9 +453,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int256 - Negative Base Case', async () => {
             // Create DataType object
@@ -505,9 +467,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int256 - Positive Value', async () => {
             // Create DataType object
@@ -521,9 +481,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int256 - Negative Value', async () => {
             // Create DataType object
@@ -537,9 +495,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int256 - Value too large', async () => {
             // Create DataType object
@@ -575,9 +531,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int32 - Negative Base Case', async () => {
             // Create DataType object
@@ -591,9 +545,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int32 - Positive Value', async () => {
             // Create DataType object
@@ -607,9 +559,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int32 - Negative Value', async () => {
             // Create DataType object
@@ -623,9 +573,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Int32 - Value too large', async () => {
             // Create DataType object
@@ -671,9 +619,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('UInt256 - Positive Value', async () => {
             // Create DataType object
@@ -687,9 +633,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('UInt256 - Zero Value', async () => {
             // Create DataType object
@@ -703,9 +647,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('UInt256 - Value too large', async () => {
             // Create DataType object
@@ -741,9 +683,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('UInt32 - Positive Value', async () => {
             // Create DataType object
@@ -757,9 +697,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('UInt32 - Zero Value', async () => {
             // Create DataType object
@@ -773,9 +711,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('UInt32 - Value too large', async () => {
             // Create DataType object
@@ -814,9 +750,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Single Byte (bytes1)', async () => {
             // Create DataType object
@@ -830,9 +764,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('4 Bytes (bytes4)', async () => {
             // Create DataType object
@@ -846,9 +778,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('4 Bytes (bytes4); Encoder must pad input', async () => {
             // Create DataType object
@@ -863,10 +793,8 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const paddedArgs = '0x1a180000';
-            const paddedArgsAsJson = JSON.stringify(paddedArgs);
-            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
+            expect(decodedArgs).to.be.deep.equal(paddedArgs);
         });
         it('32 Bytes (bytes32)', async () => {
             // Create DataType object
@@ -880,9 +808,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('32 Bytes (bytes32); Encoder must pad input', async () => {
             // Create DataType object
@@ -897,10 +823,8 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
             const paddedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
-            const paddedArgsAsJson = JSON.stringify(paddedArgs);
-            expect(decodedArgsAsJson).to.be.equal(paddedArgsAsJson);
+            expect(decodedArgs).to.be.deep.equal(paddedArgs);
         });
         it('Should throw when pass in too many bytes (bytes4)', async () => {
             // Create DataType object
@@ -967,9 +891,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Spans multiple EVM words', async () => {
             // Create DataType object
@@ -986,9 +908,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Input as Buffer', async () => {
             // Create DataType object
@@ -1005,9 +925,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Should throw when pass in bad hex (no 0x prefix)', async () => {
             // Create DataType object
@@ -1048,9 +966,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('Spans multiple EVM words', async () => {
             // Create DataType object
@@ -1067,9 +983,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
         it('String that begins with 0x prefix', async () => {
             // Create DataType object
@@ -1086,9 +1000,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
             const decodedArgs = dataType.decode(encodedArgs);
-            const decodedArgsAsJson = JSON.stringify(decodedArgs);
-            const argsAsJson = JSON.stringify(args);
-            expect(decodedArgsAsJson).to.be.equal(argsAsJson);
+            expect(decodedArgs).to.be.deep.equal(args);
         });
     });
 });
diff --git a/packages/utils/test/abi_encoder/methods_test.ts b/packages/utils/test/abi_encoder/methods_test.ts
index d158b9e5b..c870f4f04 100644
--- a/packages/utils/test/abi_encoder/methods_test.ts
+++ b/packages/utils/test/abi_encoder/methods_test.ts
@@ -20,10 +20,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Array of Static Tuples (Array has defined length)', async () => {
         // Generate calldata
@@ -41,10 +39,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Array of Static Tuples (Array has dynamic length)', async () => {
         // Generate calldata
@@ -62,10 +58,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Array of Dynamic Tuples (Array has defined length)', async () => {
         // Generate Calldata
@@ -83,10 +77,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Array of Dynamic Tuples (Array has dynamic length)', async () => {
         // Generate calldata
@@ -104,10 +96,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Multidimensional Arrays / Static Members', async () => {
         // Generate calldata
@@ -129,10 +119,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         expect(calldata).to.be.equal(expectedCalldata);
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Multidimensional Arrays / Dynamic Members', async () => {
         // Generate calldata
@@ -159,10 +147,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Fixed Length Array / Dynamic Members', async () => {
         // Generate calldata
@@ -174,10 +160,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Fixed Length Array / Dynamic Members', async () => {
         // Generaet calldata
@@ -189,10 +173,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Unfixed Length Array / Dynamic Members ABI', async () => {
         // Generate calldata
@@ -204,10 +186,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Unfixed Length Array / Static Members ABI', async () => {
         // Generate calldata
@@ -219,10 +199,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Fixed Length Array / Static Members ABI', async () => {
         // Generate calldata
@@ -234,10 +212,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Array ABI', async () => {
         // Generate calldata
@@ -249,10 +225,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Static Tuple', async () => {
         // Generate calldata
@@ -265,10 +239,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Dynamic Tuple (Array input)', async () => {
         // Generate calldata
@@ -281,10 +253,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Dynamic Tuple (Object input)', async () => {
         // Generate Calldata
@@ -297,10 +267,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Large, Flat ABI', async () => {
         // Construct calldata
@@ -322,10 +290,8 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata);
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
     it('Large, Nested ABI', async () => {
         // Construct Calldata
@@ -393,9 +359,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
         // Validate decoding
-        const expectedDecodedValueJson = JSON.stringify(args);
         const decodedValue = method.decode(calldata, { structsAsObjects: true });
-        const decodedValueJson = JSON.stringify(decodedValue);
-        expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);
+        expect(decodedValue).to.be.deep.equal(args);
     });
 });
diff --git a/packages/utils/test/abi_encoder/optimizer_test.ts b/packages/utils/test/abi_encoder/optimizer_test.ts
index 304c9cbc2..27443fe48 100644
--- a/packages/utils/test/abi_encoder/optimizer_test.ts
+++ b/packages/utils/test/abi_encoder/optimizer_test.ts
@@ -23,9 +23,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Dynamic Arrays with Dynamic Elements', async () => {
         // Generate calldata
@@ -40,9 +38,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Static Arrays with Static Elements (should not optimize)', async () => {
         // Generate calldata
@@ -59,9 +55,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(unoptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Static Arrays with Dynamic Elements', async () => {
         // Generate calldata
@@ -76,9 +70,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Array Elements (should optimize)', async () => {
         // Generate calldata
@@ -92,9 +84,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Tuple Fields', async () => {
         // Generate calldata
@@ -108,9 +98,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Strings', async () => {
         // Description:
@@ -127,9 +115,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Bytes', async () => {
         // Description:
@@ -147,9 +133,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Tuples', async () => {
         // Generate calldata
@@ -164,9 +148,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Fields Across Two Tuples', async () => {
         // Description:
@@ -182,9 +164,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Arrays, Nested in Separate Tuples', async () => {
         // Generate calldata
@@ -200,9 +180,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Tuples, Nested in Separate Tuples', async () => {
         // Generate calldata
@@ -218,9 +196,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Two-Dimensional Arrays', async () => {
         // Generate calldata
@@ -235,9 +211,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Duplicate Array, Nested within Separate Two-Dimensional Arrays', async () => {
         // Generate calldata
@@ -252,9 +226,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Array Elements Duplicated as Tuple Fields', async () => {
         // Generate calldata
@@ -269,9 +241,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
     it('Array Elements Duplicated as Separate Parameter', async () => {
         // Generate calldata
@@ -286,8 +256,6 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
         // Validate decoding
         const decodedArgs = method.decode(optimizedCalldata);
-        const decodedArgsJson = JSON.stringify(decodedArgs);
-        const argsJson = JSON.stringify(args);
-        expect(decodedArgsJson).to.be.equal(argsJson);
+        expect(decodedArgs).to.be.deep.equal(args);
     });
 });
diff --git a/packages/utils/test/abi_encoder/return_values_test.ts b/packages/utils/test/abi_encoder/return_values_test.ts
index 850cb1746..3215509f1 100644
--- a/packages/utils/test/abi_encoder/return_values_test.ts
+++ b/packages/utils/test/abi_encoder/return_values_test.ts
@@ -16,9 +16,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         const returnValue = '0x';
         const decodedReturnValue = method.decodeReturnValues(returnValue);
         const expectedDecodedReturnValue: any[] = [];
-        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-        const expectedDecodedReturnValueJson = JSON.stringify(expectedDecodedReturnValue);
-        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        expect(decodedReturnValue).to.be.deep.equal(expectedDecodedReturnValue);
     });
     it('Single static return value', async () => {
         // Generate Return Value
@@ -27,9 +25,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         const encodedReturnValue = method.encodeReturnValues(returnValue);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
-        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        expect(decodedReturnValue).to.be.deep.equal(returnValue);
     });
     it('Multiple static return values', async () => {
         // Generate Return Value
@@ -38,9 +34,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         const encodedReturnValue = method.encodeReturnValues(returnValue);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
-        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        expect(decodedReturnValue).to.be.deep.equal(returnValue);
     });
     it('Single dynamic return value', async () => {
         // Generate Return Value
@@ -49,9 +43,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         const encodedReturnValue = method.encodeReturnValues(returnValue);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
-        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        expect(decodedReturnValue).to.be.deep.equal(returnValue);
     });
     it('Multiple dynamic return values', async () => {
         // Generate Return Value
@@ -60,9 +52,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         const encodedReturnValue = method.encodeReturnValues(returnValue);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
-        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        expect(decodedReturnValue).to.be.deep.equal(returnValue);
     });
     it('Mixed static/dynamic return values', async () => {
         // Generate Return Value
@@ -71,8 +61,6 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         const encodedReturnValue = method.encodeReturnValues(returnValue);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
-        const decodedReturnValueJson = JSON.stringify(decodedReturnValue);
-        const expectedDecodedReturnValueJson = JSON.stringify(returnValue);
-        expect(decodedReturnValueJson).to.be.equal(expectedDecodedReturnValueJson);
+        expect(decodedReturnValue).to.be.deep.equal(returnValue);
     });
 });
-- 
cgit v1.2.3


From f31d4ddffd8dd97f2b2dc226f4f132d1c3192c76 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 13:10:34 -0800
Subject: Replaced null/undefined checks with lodash

---
 .../abi_encoder/abstract_data_types/types/set.ts   | 22 +++++++++++-----------
 .../src/abi_encoder/calldata/blocks/pointer.ts     |  3 ++-
 .../utils/src/abi_encoder/calldata/calldata.ts     |  8 ++++----
 .../utils/src/abi_encoder/calldata/iterator.ts     |  4 ++--
 .../utils/src/abi_encoder/calldata/raw_calldata.ts |  3 ++-
 .../utils/src/abi_encoder/evm_data_types/array.ts  | 13 +++++++------
 .../utils/src/abi_encoder/evm_data_types/int.ts    |  3 ++-
 .../src/abi_encoder/evm_data_types/static_bytes.ts |  2 +-
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |  3 ++-
 9 files changed, 33 insertions(+), 28 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 427122ad6..5a188d6fa 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -32,7 +32,7 @@ export abstract class Set extends DataType {
         this._isArray = isArray;
         this._arrayLength = arrayLength;
         this._arrayElementType = arrayElementType;
-        if (isArray && arrayLength !== undefined) {
+        if (isArray && !_.isUndefined(arrayLength)) {
             [this._members, this._memberIndexByName] = this._createMembersWithLength(dataItem, arrayLength);
         } else if (!isArray) {
             [this._members, this._memberIndexByName] = this._createMembersWithKeys(dataItem);
@@ -51,7 +51,7 @@ export abstract class Set extends DataType {
         let members = this._members;
         // Case 1: This is an array of undefined length, which means that `this._members` was not
         //         populated in the constructor. So, construct the set of members it now.
-        if (this._isArray && this._arrayLength === undefined) {
+        if (this._isArray && _.isUndefined(this._arrayLength)) {
             const arrayLengthBuf = calldata.popWord();
             const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
             const arrayLength = new BigNumber(arrayLengthHex, Constants.HEX_BASE);
@@ -83,20 +83,20 @@ export abstract class Set extends DataType {
 
     public isStatic(): boolean {
         // An array with an undefined length is never static.
-        if (this._isArray && this._arrayLength === undefined) {
+        if (this._isArray && _.isUndefined(this._arrayLength)) {
             return false;
         }
         // If any member of the set is a pointer then the set is not static.
         const dependentMember = _.find(this._members, (member: DataType) => {
             return member instanceof Pointer;
         });
-        const isStatic = dependentMember === undefined;
+        const isStatic = _.isUndefined(dependentMember);
         return isStatic;
     }
 
     protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): CalldataBlocks.Set {
         // Sanity check: if the set has a defined length then `value` must have the same length.
-        if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
+        if (!_.isUndefined(this._arrayLength) && value.length !== this._arrayLength) {
             throw new Error(
                 `Expected array of ${JSON.stringify(
                     this._arrayLength,
@@ -104,7 +104,7 @@ export abstract class Set extends DataType {
             );
         }
         // Create a new calldata block for this set.
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
         const block: CalldataBlocks.Set = new CalldataBlocks.Set(
             this.getDataItem().name,
             this.getSignature(),
@@ -112,7 +112,7 @@ export abstract class Set extends DataType {
         );
         // If this set has an undefined length then set its header to be the number of elements.
         let members = this._members;
-        if (this._isArray && this._arrayLength === undefined) {
+        if (this._isArray && _.isUndefined(this._arrayLength)) {
             [members] = this._createMembersWithLength(this.getDataItem(), value.length);
             const lenBuf = ethUtil.setLengthLeft(
                 ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
@@ -132,7 +132,7 @@ export abstract class Set extends DataType {
 
     protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
         // Create a new calldata block for this set.
-        const parentName = parentBlock === undefined ? '' : parentBlock.getName();
+        const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
         const block: CalldataBlocks.Set = new CalldataBlocks.Set(
             this.getDataItem().name,
             this.getSignature(),
@@ -175,7 +175,7 @@ export abstract class Set extends DataType {
 
     private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] {
         // Sanity check
-        if (dataItem.components === undefined) {
+        if (_.isUndefined(dataItem.components)) {
             throw new Error(`Expected components`);
         }
         // Create one member for each component of `dataItem`
@@ -187,7 +187,7 @@ export abstract class Set extends DataType {
                 name: `${dataItem.name}.${memberItem.name}`,
             };
             const components = memberItem.components;
-            if (components !== undefined) {
+            if (!_.isUndefined(components)) {
                 childDataItem.components = components;
             }
             const child = this.getFactory().create(childDataItem, this);
@@ -208,7 +208,7 @@ export abstract class Set extends DataType {
                 name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
             };
             const components = dataItem.components;
-            if (components !== undefined) {
+            if (!_.isUndefined(components)) {
                 memberDataItem.components = components;
             }
             const memberType = this.getFactory().create(memberDataItem, this);
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
index 1c49a8c6c..654cbe26c 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
@@ -1,4 +1,5 @@
 import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
 
 import * as Constants from '../../utils/constants';
 
@@ -24,7 +25,7 @@ export class Pointer extends CalldataBlock {
 
     public toBuffer(): Buffer {
         const destinationOffset =
-            this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
+            !_.isUndefined(this._aliasFor) ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
         const parentOffset = this._parent.getOffsetInBytes();
         const parentHeaderSize = this._parent.getHeaderSizeInBytes();
         const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index a662f30b9..e93d63803 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -44,7 +44,7 @@ export class Calldata {
      */
     public toString(): string {
         // Sanity check: root block must be set
-        if (this._root === undefined) {
+        if (_.isUndefined(this._root)) {
             throw new Error('expected root');
         }
         // Optimize, if flag set
@@ -103,7 +103,7 @@ export class Calldata {
      */
     private _optimize(): void {
         // Step 1/1 Create a reverse iterator (starts from the end of the calldata to the beginning)
-        if (this._root === undefined) {
+        if (_.isUndefined(this._root)) {
             throw new Error('expected root');
         }
         const iterator = new ReverseCalldataIterator(this._root);
@@ -136,7 +136,7 @@ export class Calldata {
      */
     private _toCondensedString(): string {
         // Sanity check: must have a root block.
-        if (this._root === undefined) {
+        if (_.isUndefined(this._root)) {
             throw new Error('expected root');
         }
         // Construct an array of buffers (one buffer for each block).
@@ -175,7 +175,7 @@ export class Calldata {
      */
     private _toAnnotatedString(): string {
         // Sanity check: must have a root block.
-        if (this._root === undefined) {
+        if (_.isUndefined(this._root)) {
             throw new Error('expected root');
         }
         // Constants for constructing annotated string
diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts
index 8e2b16a5a..5307f7944 100644
--- a/packages/utils/src/abi_encoder/calldata/iterator.ts
+++ b/packages/utils/src/abi_encoder/calldata/iterator.ts
@@ -55,7 +55,7 @@ abstract class BaseIterator implements Iterable<CalldataBlock> {
         _.each(set.getMembers(), (member: CalldataBlock) => {
             // Traverse child if it is a unique pointer.
             // A pointer that is an alias for another pointer is ignored.
-            if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) {
+            if (member instanceof CalldataBlocks.Pointer && _.isUndefined(member.getAlias())) {
                 const dependency = member.getDependency();
                 queue.mergeBack(BaseIterator._createQueue(dependency));
             }
@@ -74,7 +74,7 @@ abstract class BaseIterator implements Iterable<CalldataBlock> {
         return {
             next: () => {
                 const nextBlock = this.nextBlock();
-                if (nextBlock !== undefined) {
+                if (!_.isUndefined(nextBlock)) {
                     return {
                         value: nextBlock,
                         done: false,
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index b13cbdfd9..dfd4cfa72 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -1,4 +1,5 @@
 import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
 
 import * as Constants from '../utils/constants';
 import { Queue } from '../utils/queue';
@@ -68,7 +69,7 @@ export class RawCalldata {
 
     public toAbsoluteOffset(relativeOffset: number): number {
         const scopeOffset = this._scopes.peekFront();
-        if (scopeOffset === undefined) {
+        if (_.isUndefined(scopeOffset)) {
             throw new Error(`Tried to access undefined scope.`);
         }
         const absoluteOffset = relativeOffset + scopeOffset;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 8cf2cf7cf..a86283c2a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -1,4 +1,5 @@
 import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import * as Constants from '../utils/constants';
@@ -14,15 +15,15 @@ export class Array extends AbstractDataTypes.Set {
 
     private static _decodeElementTypeAndLengthFromType(type: string): [string, undefined | number] {
         const matches = Array._MATCHER.exec(type);
-        if (matches === null || matches.length !== 3) {
+        if (_.isNull(matches) || matches.length !== 3) {
             throw new Error(`Could not parse array: ${type}`);
-        } else if (matches[1] === undefined) {
+        } else if (_.isUndefined(matches[1])) {
             throw new Error(`Could not parse array type: ${type}`);
-        } else if (matches[2] === undefined) {
+        } else if (_.isUndefined(matches[2])) {
             throw new Error(`Could not parse array length: ${type}`);
         }
         const arrayElementType = matches[1];
-        const arrayLength = matches[2] === '' ? undefined : parseInt(matches[2], Constants.DEC_BASE);
+        const arrayLength = _.isEmpty(matches[2]) ? undefined : parseInt(matches[2], Constants.DEC_BASE);
         return [arrayElementType, arrayLength];
     }
 
@@ -47,13 +48,13 @@ export class Array extends AbstractDataTypes.Set {
             name: 'N/A',
         };
         const elementComponents = this.getDataItem().components;
-        if (elementComponents !== undefined) {
+        if (!_.isUndefined(elementComponents)) {
             elementDataItem.components = elementComponents;
         }
         const elementDataType = this.getFactory().create(elementDataItem);
         const elementSignature = elementDataType.getSignature();
         // Construct signature for array of type `element`
-        if (this._arrayLength === undefined) {
+        if (_.isUndefined(this._arrayLength)) {
             return `${elementSignature}[]`;
         } else {
             return `${elementSignature}[${this._arrayLength}]`;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 032cd045a..5c5193644 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -1,5 +1,6 @@
 /* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
@@ -25,7 +26,7 @@ export class Int extends AbstractDataTypes.Blob {
     private static _decodeWidthFromType(type: string): number {
         const matches = Int._MATCHER.exec(type);
         const width =
-            matches !== null && matches.length === 2 && matches[1] !== undefined
+            !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
                 ? parseInt(matches[1], Constants.DEC_BASE)
                 : Int._DEFAULT_WIDTH;
         return width;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 2c649cb33..3a2ad410f 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -21,7 +21,7 @@ export class StaticBytes extends AbstractDataTypes.Blob {
     private static _decodeWidthFromType(type: string): number {
         const matches = StaticBytes._MATCHER.exec(type);
         const width =
-            matches !== null && matches.length === 3 && matches[2] !== undefined
+            !_.isNull(matches) && matches.length === 3 && !_.isUndefined(matches[2])
                 ? parseInt(matches[2], Constants.DEC_BASE)
                 : StaticBytes._DEFAULT_WIDTH;
         return width;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index b5b7683a2..76b944610 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -1,5 +1,6 @@
 /* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
@@ -25,7 +26,7 @@ export class UInt extends AbstractDataTypes.Blob {
     private static _decodeWidthFromType(type: string): number {
         const matches = UInt._MATCHER.exec(type);
         const width =
-            matches !== null && matches.length === 2 && matches[1] !== undefined
+            !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
                 ? parseInt(matches[1], Constants.DEC_BASE)
                 : UInt._DEFAULT_WIDTH;
         return width;
-- 
cgit v1.2.3


From 3f545da9f86856b54cd226c29174ac1ae085e35b Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 13:28:17 -0800
Subject: Switched implicit conversions to explicit lodash calls

---
 .../utils/src/abi_encoder/abstract_data_types/data_type.ts   | 12 ++++++------
 .../utils/src/abi_encoder/abstract_data_types/types/blob.ts  |  2 +-
 .../utils/src/abi_encoder/abstract_data_types/types/set.ts   |  2 +-
 packages/utils/src/abi_encoder/evm_data_types/bool.ts        |  2 +-
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index ab7df6ecc..61d3ac3a9 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -25,9 +25,9 @@ export abstract class DataType {
     }
 
     public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = rules ? rules : Constants.DEFAULT_ENCODING_RULES;
+        const rules_ = _.isUndefined(rules) ? Constants.DEFAULT_ENCODING_RULES : rules;
         const calldata = new Calldata(rules_);
-        if (selector) {
+        if (!_.isUndefined(selector)) {
             calldata.setSelector(selector);
         }
         const block = this.generateCalldataBlock(value);
@@ -37,14 +37,14 @@ export abstract class DataType {
     }
 
     public decode(calldata: string, rules?: DecodingRules, selector?: string): any {
-        if (selector && !calldata.startsWith(selector)) {
+        if (!_.isUndefined(selector) && !calldata.startsWith(selector)) {
             throw new Error(
-                `Tried to decode calldata, but it was missing the function selector. Expected '${selector}'.`,
+                `Tried to decode calldata, but it was missing the function selector. Expected prefix '${selector}'. Got '${calldata}'.`,
             );
         }
-        const hasSelector = selector ? true : false;
+        const hasSelector = !_.isUndefined(selector);
         const rawCalldata = new RawCalldata(calldata, hasSelector);
-        const rules_ = rules ? rules : Constants.DEFAULT_DECODING_RULES;
+        const rules_ = _.isUndefined(rules) ? Constants.DEFAULT_DECODING_RULES : rules;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
     }
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
index 35ccc0586..965738056 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -19,7 +19,7 @@ export abstract class Blob extends DataType {
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
-        const parentName = parentBlock ? parentBlock.getName() : '';
+        const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
         const block = new CalldataBlocks.Blob(name, signature, parentName, encodedValue);
         return block;
     }
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 5a188d6fa..637abfb7d 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -204,7 +204,7 @@ export abstract class Set extends DataType {
         const range = _.range(length);
         _.each(range, (idx: number) => {
             const memberDataItem: DataItem = {
-                type: this._arrayElementType ? this._arrayElementType : '',
+                type: _.isUndefined(this._arrayElementType) ? '' : this._arrayElementType,
                 name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
             };
             const components = dataItem.components;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 031acc88a..fa115bb87 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -39,7 +39,7 @@ export class Bool extends AbstractDataTypes.Blob {
             throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
         }
         /* tslint:disable boolean-naming */
-        const value: boolean = valueNumber.equals(0) ? false : true;
+        const value: boolean = !valueNumber.equals(0);
         /* tslint:enable boolean-naming */
         return value;
     }
-- 
cgit v1.2.3


From 1f693ea12142bc761f4067871d92e7d2662cf256 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 13:31:44 -0800
Subject: Changed from <string>.startsWith to _.startsWith

---
 packages/utils/src/abi_encoder/abstract_data_types/data_type.ts | 2 +-
 packages/utils/src/abi_encoder/calldata/calldata.ts             | 2 +-
 packages/utils/src/abi_encoder/calldata/raw_calldata.ts         | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/address.ts        | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts  | 2 +-
 packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts   | 2 +-
 packages/utils/src/abi_encoder/utils/math.ts                    | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index 61d3ac3a9..4cef60172 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -37,7 +37,7 @@ export abstract class DataType {
     }
 
     public decode(calldata: string, rules?: DecodingRules, selector?: string): any {
-        if (!_.isUndefined(selector) && !calldata.startsWith(selector)) {
+        if (!_.isUndefined(selector) && !_.startsWith(calldata, selector)) {
             throw new Error(
                 `Tried to decode calldata, but it was missing the function selector. Expected prefix '${selector}'. Got '${calldata}'.`,
             );
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index e93d63803..c57ff08c2 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -29,7 +29,7 @@ export class Calldata {
      * If the root block was created by a Method then a selector will likely be set.
      */
     public setSelector(selector: string): void {
-        if (!selector.startsWith('0x')) {
+        if (!_.startsWith(selector, '0x')) {
             throw new Error(`Expected selector to be hex. Missing prefix '0x'`);
         } else if (selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
             throw new Error(`Invalid selector '${selector}'`);
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index dfd4cfa72..fbe592fc7 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -13,7 +13,7 @@ export class RawCalldata {
 
     public constructor(value: string | Buffer, hasSelector: boolean = true) {
         // Sanity check
-        if (typeof value === 'string' && !value.startsWith('0x')) {
+        if (typeof value === 'string' && !_.startsWith(value, '0x')) {
             throw new Error(`Expected raw calldata to start with '0x'`);
         }
         // Construct initial values
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 71aa293b5..52fc8e7b9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -31,7 +31,7 @@ export class Address extends AbstractDataTypes.Blob {
     }
 
     public encodeValue(value: string): Buffer {
-        if (!value.startsWith('0x')) {
+        if (!_.startsWith(value, '0x')) {
             throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
         }
         const valueBuf = ethUtil.toBuffer(value);
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index 01d83d11a..98d90b7e4 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -60,7 +60,7 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         if (typeof value !== 'string') {
             return;
         }
-        if (!value.startsWith('0x')) {
+        if (!_.startsWith(value, '0x')) {
             throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
         } else if (value.length % 2 !== 0) {
             throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 3a2ad410f..68f212f79 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -59,7 +59,7 @@ export class StaticBytes extends AbstractDataTypes.Blob {
 
     private _sanityCheckValue(value: string | Buffer): void {
         if (typeof value === 'string') {
-            if (!value.startsWith('0x')) {
+            if (!_.startsWith(value, '0x')) {
                 throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
             } else if (value.length % 2 !== 0) {
                 throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
diff --git a/packages/utils/src/abi_encoder/utils/math.ts b/packages/utils/src/abi_encoder/utils/math.ts
index c5fa10e73..bc344c695 100644
--- a/packages/utils/src/abi_encoder/utils/math.ts
+++ b/packages/utils/src/abi_encoder/utils/math.ts
@@ -79,7 +79,7 @@ export function decodeNumericValue(encodedValue: Buffer, minValue: BigNumber): B
     }
     // Case 2/3: value is non-negative because there is no leading 1 (encoded as two's-complement)
     const valueBin = value.toString(Constants.BIN_BASE);
-    const valueIsNegative = valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && valueBin[0].startsWith('1');
+    const valueIsNegative = valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && _.startsWith(valueBin[0], '1');
     if (!valueIsNegative) {
         return value;
     }
-- 
cgit v1.2.3


From ffb8b0a619be3b8fb30a6acc99f590a6b40d49e1 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 13:35:39 -0800
Subject: Changed remaining instances of implicit `bool` casts to explicit
 lodash calls

---
 packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts | 2 +-
 packages/utils/src/abi_encoder/calldata/blocks/set.ts               | 4 ++--
 packages/utils/src/abi_encoder/evm_data_type_factory.ts             | 5 +++--
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index 46e60979a..dc9de8a3d 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -21,7 +21,7 @@ export abstract class Pointer extends DataType {
     }
 
     public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Pointer {
-        if (!parentBlock) {
+        if (_.isUndefined(parentBlock)) {
             throw new Error(`DependentDataType requires a parent block to generate its block`);
         }
         const destinationBlock = this._destination.generateCalldataBlock(value, parentBlock);
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts
index e4de22c5c..81455b364 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/set.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts
@@ -14,7 +14,7 @@ export class Set extends CalldataBlock {
 
     public getRawData(): Buffer {
         const rawDataComponents: Buffer[] = [];
-        if (this._header) {
+        if (!_.isUndefined(this._header)) {
             rawDataComponents.push(this._header);
         }
         _.each(this._members, (member: CalldataBlock) => {
@@ -35,7 +35,7 @@ export class Set extends CalldataBlock {
     }
 
     public toBuffer(): Buffer {
-        if (this._header) {
+        if (!_.isUndefined(this._header)) {
             return this._header;
         }
         return new Buffer('');
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index bfe457367..16a0b724d 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -2,6 +2,7 @@
 /* tslint:disable max-classes-per-file */
 /* tslint:disable no-construct */
 import { DataItem, MethodAbi } from 'ethereum-types';
+import * as _ from 'lodash';
 
 import { DataType, DataTypeFactory } from './abstract_data_types';
 import * as Impl from './evm_data_types';
@@ -105,9 +106,9 @@ export class EvmDataTypeFactory implements DataTypeFactory {
             dataType = new String(dataItem);
         }
         // @TODO: Implement Fixed/UFixed types
-        if (!dataType) {
+        if (_.isUndefined(dataType)) {
             throw new Error(`Unrecognized data type: '${dataItem.type}'`);
-        } else if (parentDataType && !dataType.isStatic()) {
+        } else if (!_.isUndefined(parentDataType) && !dataType.isStatic()) {
             const pointerToDataType = new Pointer(dataType, parentDataType);
             return pointerToDataType;
         }
-- 
cgit v1.2.3


From f479212410b238a7673983148f403b3a220083af Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 15:28:26 -0800
Subject: Style cleanup. Improved wording of some error messages.

---
 .../abstract_data_types/types/pointer.ts           |  4 +++-
 .../abi_encoder/abstract_data_types/types/set.ts   |  4 ++--
 .../utils/src/abi_encoder/calldata/calldata.ts     | 11 ++++-----
 .../utils/src/abi_encoder/evm_data_type_factory.ts |  6 +++--
 .../src/abi_encoder/evm_data_types/address.ts      | 12 ++++++----
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |  4 +++-
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    | 28 ++++++++++++----------
 .../utils/src/abi_encoder/evm_data_types/int.ts    |  1 -
 .../utils/src/abi_encoder/evm_data_types/string.ts |  4 +++-
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |  1 -
 packages/utils/src/abi_encoder/utils/math.ts       |  4 ++--
 11 files changed, 43 insertions(+), 36 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index dc9de8a3d..8e597636b 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method  */
 import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
@@ -44,7 +43,10 @@ export abstract class Pointer extends DataType {
         return value;
     }
 
+    // Disable prefer-function-over-method for inherited abstract method.
+    /* tslint:disable prefer-function-over-method */
     public isStatic(): boolean {
         return true;
     }
+    /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 637abfb7d..aeea7919f 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -50,7 +50,7 @@ export abstract class Set extends DataType {
     public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
         let members = this._members;
         // Case 1: This is an array of undefined length, which means that `this._members` was not
-        //         populated in the constructor. So, construct the set of members it now.
+        //         populated in the constructor. So we must construct the set of members now.
         if (this._isArray && _.isUndefined(this._arrayLength)) {
             const arrayLengthBuf = calldata.popWord();
             const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
@@ -176,7 +176,7 @@ export abstract class Set extends DataType {
     private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] {
         // Sanity check
         if (_.isUndefined(dataItem.components)) {
-            throw new Error(`Expected components`);
+            throw new Error(`Tried to create a set using key/value pairs, but no components were defined by the input DataItem '${dataItem.name}'.`);
         }
         // Create one member for each component of `dataItem`
         const members: DataType[] = [];
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index c57ff08c2..6d8814e06 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -59,7 +59,7 @@ export class Calldata {
             offset += block.getSizeInBytes();
         }
         // Generate hex string
-        const hexString = this._rules.annotate ? this._toAnnotatedString() : this._toCondensedString();
+        const hexString = this._rules.annotate ? this._toHumanReadableCallData() : this._toEvmCompatibeCallDataHex();
         return hexString;
     }
     /**
@@ -131,10 +131,7 @@ export class Calldata {
             }
         }
     }
-    /**
-     * Returns EVM-compatible calldata as a Hex string.
-     */
-    private _toCondensedString(): string {
+    private _toEvmCompatibeCallDataHex(): string {
         // Sanity check: must have a root block.
         if (_.isUndefined(this._root)) {
             throw new Error('expected root');
@@ -152,7 +149,7 @@ export class Calldata {
         return hexValue;
     }
     /**
-     * Returns human-redable calldata.
+     * Returns human-readable calldata.
      *
      * Example:
      *   simpleFunction(string[], string[])
@@ -173,7 +170,7 @@ export class Calldata {
      *   0xe0      0000000000000000000000000000000000000000000000000000000000000005              array2[1]
      *   0x100     576f726c64000000000000000000000000000000000000000000000000000000
      */
-    private _toAnnotatedString(): string {
+    private _toHumanReadableCallData(): string {
         // Sanity check: must have a root block.
         if (_.isUndefined(this._root)) {
             throw new Error('expected root');
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index 16a0b724d..bc68e05b7 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -1,6 +1,4 @@
-/* tslint:disable prefer-function-over-method */
 /* tslint:disable max-classes-per-file */
-/* tslint:disable no-construct */
 import { DataItem, MethodAbi } from 'ethereum-types';
 import * as _ from 'lodash';
 
@@ -73,6 +71,7 @@ export class Method extends Impl.Method {
     }
 }
 
+/* tslint:disable no-construct */
 export class EvmDataTypeFactory implements DataTypeFactory {
     private static _instance: DataTypeFactory;
 
@@ -83,6 +82,7 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         return EvmDataTypeFactory._instance;
     }
 
+    /* tslint:disable prefer-function-over-method */
     public create(dataItem: DataItem, parentDataType?: DataType): DataType {
         // Create data type
         let dataType: undefined | DataType;
@@ -114,6 +114,8 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         }
         return dataType;
     }
+    /* tslint:enable prefer-function-over-method */
 
     private constructor() {}
 }
+/* tslint:enable no-construct */
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 52fc8e7b9..25ff55903 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
@@ -26,10 +25,8 @@ export class Address extends AbstractDataTypes.Blob {
         }
     }
 
-    public getSignature(): string {
-        return 'address';
-    }
-
+    // Disable prefer-function-over-method for inherited abstract methods.
+    /* tslint:disable prefer-function-over-method */
     public encodeValue(value: string): Buffer {
         if (!_.startsWith(value, '0x')) {
             throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
@@ -48,4 +45,9 @@ export class Address extends AbstractDataTypes.Blob {
         const value = ethUtil.bufferToHex(valueBuf);
         return value;
     }
+
+    public getSignature(): string {
+        return 'address';
+    }
+    /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index fa115bb87..7e135aba9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
@@ -22,6 +21,8 @@ export class Bool extends AbstractDataTypes.Blob {
         }
     }
 
+    // Disable prefer-function-over-method for inherited abstract methods.
+    /* tslint:disable prefer-function-over-method */
     public encodeValue(value: boolean): Buffer {
         const encodedValue = value ? '0x1' : '0x0';
         const encodedValueBuf = ethUtil.setLengthLeft(
@@ -47,4 +48,5 @@ export class Bool extends AbstractDataTypes.Blob {
     public getSignature(): string {
         return 'bool';
     }
+    /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index 98d90b7e4..ad22c8c6e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
@@ -14,6 +13,17 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         return type === 'bytes';
     }
 
+    private static _sanityCheckValue(value: string | Buffer): void {
+        if (typeof value !== 'string') {
+            return;
+        }
+        if (!_.startsWith(value, '0x')) {
+            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
+        } else if (value.length % 2 !== 0) {
+            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
+        }
+    }
+
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         super(dataItem, dataTypeFactory, DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
         if (!DynamicBytes.matchType(dataItem.type)) {
@@ -21,6 +31,8 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         }
     }
 
+    // Disable prefer-function-over-method for inherited abstract methods.
+    /* tslint:disable prefer-function-over-method */
     public encodeValue(value: string | Buffer): Buffer {
         // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
         // 1/3 Construct the length
@@ -48,22 +60,12 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
         const valueBuf = valueBufPadded.slice(0, length);
         const value = ethUtil.bufferToHex(valueBuf);
-        this._sanityCheckValue(value);
+        DynamicBytes._sanityCheckValue(value);
         return value;
     }
 
     public getSignature(): string {
         return 'bytes';
     }
-
-    private _sanityCheckValue(value: string | Buffer): void {
-        if (typeof value !== 'string') {
-            return;
-        }
-        if (!_.startsWith(value, '0x')) {
-            throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
-        } else if (value.length % 2 !== 0) {
-            throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
-        }
-    }
+    /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 5c5193644..9d328bba9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 6ab3513c9..08f928d8a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
@@ -21,6 +20,8 @@ export class String extends AbstractDataTypes.Blob {
         }
     }
 
+    // Disable prefer-function-over-method for inherited abstract methods.
+    /* tslint:disable prefer-function-over-method */
     public encodeValue(value: string): Buffer {
         // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
         // 1/3 Construct the length
@@ -53,4 +54,5 @@ export class String extends AbstractDataTypes.Blob {
     public getSignature(): string {
         return 'string';
     }
+    /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index 76b944610..4357f15d2 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -1,4 +1,3 @@
-/* tslint:disable prefer-function-over-method */
 import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
diff --git a/packages/utils/src/abi_encoder/utils/math.ts b/packages/utils/src/abi_encoder/utils/math.ts
index bc344c695..9bcdc3af1 100644
--- a/packages/utils/src/abi_encoder/utils/math.ts
+++ b/packages/utils/src/abi_encoder/utils/math.ts
@@ -79,8 +79,8 @@ export function decodeNumericValue(encodedValue: Buffer, minValue: BigNumber): B
     }
     // Case 2/3: value is non-negative because there is no leading 1 (encoded as two's-complement)
     const valueBin = value.toString(Constants.BIN_BASE);
-    const valueIsNegative = valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && _.startsWith(valueBin[0], '1');
-    if (!valueIsNegative) {
+    const isValueNegative = valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && _.startsWith(valueBin[0], '1');
+    if (!isValueNegative) {
         return value;
     }
     // Case 3/3: value is negative
-- 
cgit v1.2.3


From e7bdf4717da9d1fd50cda3dba4e9549dfbc337f7 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 15:32:50 -0800
Subject: Fixed build error: was using `this` instead of class name to
 reference a static function that used to be an instance method.

---
 packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index ad22c8c6e..fecd1db6b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -42,7 +42,7 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         const lengthBuf = ethUtil.toBuffer(valueBuf.byteLength);
         const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
         // 2/3 Construct the value
-        this._sanityCheckValue(value);
+        DynamicBytes._sanityCheckValue(value);
         const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
         // 3/3 Combine length and value
         const encodedValue = Buffer.concat([lengthBufPadded, valueBufPadded]);
-- 
cgit v1.2.3


From f196dc9e35d12aad281142371af4d2c32db1fd60 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 16:20:56 -0800
Subject: Use ethUti.isValidAddress in encoder

---
 packages/utils/src/abi_encoder/evm_data_types/address.ts | 9 ++-------
 packages/utils/test/abi_encoder/evm_data_types_test.ts   | 4 ++--
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 25ff55903..950901ea8 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -7,8 +7,6 @@ import { RawCalldata } from '../calldata';
 import * as Constants from '../utils/constants';
 
 export class Address extends AbstractDataTypes.Blob {
-    public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'";
-    public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes';
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
@@ -28,13 +26,10 @@ export class Address extends AbstractDataTypes.Blob {
     // Disable prefer-function-over-method for inherited abstract methods.
     /* tslint:disable prefer-function-over-method */
     public encodeValue(value: string): Buffer {
-        if (!_.startsWith(value, '0x')) {
-            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+        if (!ethUtil.isValidAddress(value)) {
+            throw new Error(`Invalid address: '${value}'`);
         }
         const valueBuf = ethUtil.toBuffer(value);
-        if (valueBuf.byteLength !== Address._ADDRESS_SIZE_IN_BYTES) {
-            throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
-        }
         const encodedValueBuf = ethUtil.setLengthLeft(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
         return encodedValueBuf;
     }
diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts
index b99500265..11cebda55 100644
--- a/packages/utils/test/abi_encoder/evm_data_types_test.ts
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -387,7 +387,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Encode Args and validate result
             expect(() => {
                 dataType.encode(args);
-            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X);
+            }).to.throw(`Invalid address: '${args}'`);
         });
         it('Invalid Address - input is not 20 bytes', async () => {
             // Create DataType object
@@ -398,7 +398,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Encode Args and validate result
             expect(() => {
                 dataType.encode(args);
-            }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES);
+            }).to.throw(`Invalid address: '${args}'`);
         });
     });
 
-- 
cgit v1.2.3


From 14c094d050e7b2d0a4b31d02dbe58a54153be7bb Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 16:33:51 -0800
Subject: Use SolidityTypes from `ethereum-types` package.

---
 packages/ethereum-types/src/index.ts                           | 5 +++++
 packages/utils/src/abi_encoder/evm_data_types/address.ts       | 6 +++---
 packages/utils/src/abi_encoder/evm_data_types/bool.ts          | 6 +++---
 packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts | 6 +++---
 packages/utils/src/abi_encoder/evm_data_types/int.ts           | 4 ++--
 packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts  | 4 ++--
 packages/utils/src/abi_encoder/evm_data_types/string.ts        | 6 +++---
 packages/utils/src/abi_encoder/evm_data_types/tuple.ts         | 4 ++--
 packages/utils/src/abi_encoder/evm_data_types/uint.ts          | 4 ++--
 9 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/packages/ethereum-types/src/index.ts b/packages/ethereum-types/src/index.ts
index eff38711a..9430fdc98 100644
--- a/packages/ethereum-types/src/index.ts
+++ b/packages/ethereum-types/src/index.ts
@@ -283,6 +283,11 @@ export interface RawLogEntry {
 
 export enum SolidityTypes {
     Address = 'address',
+    Bool = 'bool',
+    Bytes = 'bytes',
+    Int = 'int',
+    String = 'string',
+    Tuple = 'tuple',
     Uint256 = 'uint256',
     Uint8 = 'uint8',
     Uint = 'uint',
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 950901ea8..07a0bd10c 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
@@ -13,7 +13,7 @@ export class Address extends AbstractDataTypes.Blob {
     Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
-        return type === 'address';
+        return type === SolidityTypes.Address;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
@@ -42,7 +42,7 @@ export class Address extends AbstractDataTypes.Blob {
     }
 
     public getSignature(): string {
-        return 'address';
+        return SolidityTypes.Address;
     }
     /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 7e135aba9..7af13506b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
@@ -11,7 +11,7 @@ export class Bool extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
     public static matchType(type: string): boolean {
-        return type === 'bool';
+        return type === SolidityTypes.Bool;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
@@ -46,7 +46,7 @@ export class Bool extends AbstractDataTypes.Blob {
     }
 
     public getSignature(): string {
-        return 'bool';
+        return SolidityTypes.Bool;
     }
     /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index fecd1db6b..ac2a1fb6e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
@@ -10,7 +10,7 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
-        return type === 'bytes';
+        return type === SolidityTypes.Bytes;
     }
 
     private static _sanityCheckValue(value: string | Buffer): void {
@@ -65,7 +65,7 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
     }
 
     public getSignature(): string {
-        return 'bytes';
+        return SolidityTypes.Bytes;
     }
     /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 9d328bba9..3e465fc15 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
@@ -53,6 +53,6 @@ export class Int extends AbstractDataTypes.Blob {
     }
 
     public getSignature(): string {
-        return `int${this._width}`;
+        return `${SolidityTypes.Int}${this._width}`;
     }
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 68f212f79..ed1f51f7e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
@@ -37,7 +37,7 @@ export class StaticBytes extends AbstractDataTypes.Blob {
 
     public getSignature(): string {
         // Note that `byte` reduces to `bytes1`
-        return `bytes${this._width}`;
+        return `${SolidityTypes.Bytes}${this._width}`;
     }
 
     public encodeValue(value: string | Buffer): Buffer {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 08f928d8a..e5b2d5f33 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
@@ -10,7 +10,7 @@ export class String extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
-        return type === 'string';
+        return type === SolidityTypes.String;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
@@ -52,7 +52,7 @@ export class String extends AbstractDataTypes.Blob {
     }
 
     public getSignature(): string {
-        return 'string';
+        return SolidityTypes.String;
     }
     /* tslint:enable prefer-function-over-method */
 }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 3802f96c0..40859f62e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 
@@ -6,7 +6,7 @@ export class Tuple extends AbstractDataTypes.Set {
     private readonly _signature: string;
 
     public static matchType(type: string): boolean {
-        return type === 'tuple';
+        return type === SolidityTypes.Tuple;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index 4357f15d2..970400a57 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -1,4 +1,4 @@
-import { DataItem } from 'ethereum-types';
+import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
@@ -52,6 +52,6 @@ export class UInt extends AbstractDataTypes.Blob {
     }
 
     public getSignature(): string {
-        return `uint${this._width}`;
+        return `${SolidityTypes.Uint}${this._width}`;
     }
 }
-- 
cgit v1.2.3


From 029b8d59507df25aa9c7d1b096c8d873eb6ae4da Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 17:11:15 -0800
Subject: Changed constants to an exported enum; this is 0x convention

---
 .../abi_encoder/abstract_data_types/data_type.ts   |  6 +++---
 .../abstract_data_types/types/pointer.ts           |  4 ++--
 .../abi_encoder/abstract_data_types/types/set.ts   | 12 ++++++------
 .../src/abi_encoder/calldata/blocks/pointer.ts     |  6 +++---
 .../utils/src/abi_encoder/calldata/calldata.ts     | 14 +++++++-------
 .../utils/src/abi_encoder/calldata/raw_calldata.ts |  6 +++---
 .../src/abi_encoder/evm_data_types/address.ts      |  6 +++---
 .../utils/src/abi_encoder/evm_data_types/array.ts  |  4 ++--
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |  6 +++---
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    | 12 ++++++------
 .../utils/src/abi_encoder/evm_data_types/int.ts    |  4 ++--
 .../utils/src/abi_encoder/evm_data_types/method.ts |  4 ++--
 .../src/abi_encoder/evm_data_types/static_bytes.ts |  6 +++---
 .../utils/src/abi_encoder/evm_data_types/string.ts | 12 ++++++------
 .../utils/src/abi_encoder/evm_data_types/uint.ts   |  4 ++--
 packages/utils/src/abi_encoder/utils/constants.ts  | 22 ++++++++++++----------
 packages/utils/src/abi_encoder/utils/math.ts       | 20 ++++++++++----------
 17 files changed, 75 insertions(+), 73 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index 4cef60172..10e5c2540 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -2,7 +2,7 @@ import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { Calldata, CalldataBlock, RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { DataTypeFactory } from './interfaces';
@@ -25,7 +25,7 @@ export abstract class DataType {
     }
 
     public encode(value: any, rules?: EncodingRules, selector?: string): string {
-        const rules_ = _.isUndefined(rules) ? Constants.DEFAULT_ENCODING_RULES : rules;
+        const rules_ = _.isUndefined(rules) ? constants.DEFAULT_ENCODING_RULES : rules;
         const calldata = new Calldata(rules_);
         if (!_.isUndefined(selector)) {
             calldata.setSelector(selector);
@@ -44,7 +44,7 @@ export abstract class DataType {
         }
         const hasSelector = !_.isUndefined(selector);
         const rawCalldata = new RawCalldata(calldata, hasSelector);
-        const rules_ = _.isUndefined(rules) ? Constants.DEFAULT_DECODING_RULES : rules;
+        const rules_ = _.isUndefined(rules) ? constants.DEFAULT_DECODING_RULES : rules;
         const value = this.generateValue(rawCalldata, rules_);
         return value;
     }
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index 8e597636b..3d38deb94 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -3,7 +3,7 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
-import * as Constants from '../../utils/constants';
+import { constants } from '../../utils/constants';
 import { DecodingRules } from '../../utils/rules';
 
 import { DataType } from '../data_type';
@@ -34,7 +34,7 @@ export abstract class Pointer extends DataType {
     public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
         const destinationOffsetBuf = calldata.popWord();
         const destinationOffsetHex = ethUtil.bufferToHex(destinationOffsetBuf);
-        const destinationOffsetRelative = parseInt(destinationOffsetHex, Constants.HEX_BASE);
+        const destinationOffsetRelative = parseInt(destinationOffsetHex, constants.HEX_BASE);
         const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
         const currentOffset = calldata.getOffset();
         calldata.setOffset(destinationOffsetAbsolute);
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index aeea7919f..f50ed8298 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { BigNumber } from '../../../configured_bignumber';
 import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
-import * as Constants from '../../utils/constants';
+import { constants } from '../../utils/constants';
 import { DecodingRules } from '../../utils/rules';
 
 import { DataType } from '../data_type';
@@ -54,7 +54,7 @@ export abstract class Set extends DataType {
         if (this._isArray && _.isUndefined(this._arrayLength)) {
             const arrayLengthBuf = calldata.popWord();
             const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
-            const arrayLength = new BigNumber(arrayLengthHex, Constants.HEX_BASE);
+            const arrayLength = new BigNumber(arrayLengthHex, constants.HEX_BASE);
             [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
         }
         // Create a new scope in the calldata, before descending into the members of this set.
@@ -115,8 +115,8 @@ export abstract class Set extends DataType {
         if (this._isArray && _.isUndefined(this._arrayLength)) {
             [members] = this._createMembersWithLength(this.getDataItem(), value.length);
             const lenBuf = ethUtil.setLengthLeft(
-                ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
-                Constants.EVM_WORD_WIDTH_IN_BYTES,
+                ethUtil.toBuffer(`0x${value.length.toString(constants.HEX_BASE)}`),
+                constants.EVM_WORD_WIDTH_IN_BYTES,
             );
             block.setHeader(lenBuf);
         }
@@ -205,14 +205,14 @@ export abstract class Set extends DataType {
         _.each(range, (idx: number) => {
             const memberDataItem: DataItem = {
                 type: _.isUndefined(this._arrayElementType) ? '' : this._arrayElementType,
-                name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
+                name: `${dataItem.name}[${idx.toString(constants.DEC_BASE)}]`,
             };
             const components = dataItem.components;
             if (!_.isUndefined(components)) {
                 memberDataItem.components = components;
             }
             const memberType = this.getFactory().create(memberDataItem, this);
-            memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length;
+            memberIndexByName[idx.toString(constants.DEC_BASE)] = members.length;
             members.push(memberType);
         });
         return [members, memberIndexByName];
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
index 654cbe26c..1daf33f7e 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
@@ -1,7 +1,7 @@
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import * as Constants from '../../utils/constants';
+import { constants } from '../../utils/constants';
 
 import { CalldataBlock } from '../calldata_block';
 
@@ -29,9 +29,9 @@ export class Pointer extends CalldataBlock {
         const parentOffset = this._parent.getOffsetInBytes();
         const parentHeaderSize = this._parent.getHeaderSizeInBytes();
         const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
-        const pointerHex = `0x${pointer.toString(Constants.HEX_BASE)}`;
+        const pointerHex = `0x${pointer.toString(constants.HEX_BASE)}`;
         const pointerBuf = ethUtil.toBuffer(pointerHex);
-        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
         return pointerBufPadded;
     }
 
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index 6d8814e06..e5858b524 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -1,7 +1,7 @@
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 import { EncodingRules } from '../utils/rules';
 
 import * as CalldataBlocks from './blocks';
@@ -31,7 +31,7 @@ export class Calldata {
     public setSelector(selector: string): void {
         if (!_.startsWith(selector, '0x')) {
             throw new Error(`Expected selector to be hex. Missing prefix '0x'`);
-        } else if (selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
+        } else if (selector.length !== constants.HEX_SELECTOR_LENGTH_IN_CHARS) {
             throw new Error(`Invalid selector '${selector}'`);
         }
         this._selector = selector;
@@ -206,11 +206,11 @@ export class Calldata {
                 lineStr = `\n${offsetStr}${valueStr}${nameStr}`;
             } else {
                 // This block has at least one word of value.
-                offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
+                offsetStr = `0x${offset.toString(constants.HEX_BASE)}`.padEnd(offsetPadding);
                 valueStr = ethUtil
                     .stripHexPrefix(
                         ethUtil.bufferToHex(
-                            block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES),
+                            block.toBuffer().slice(evmWordStartIndex, constants.EVM_WORD_WIDTH_IN_BYTES),
                         ),
                     )
                     .padEnd(valuePadding);
@@ -223,11 +223,11 @@ export class Calldata {
                 }
             }
             // This block has a value that is more than 1 word.
-            for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) {
-                offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding);
+            for (let j = constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += constants.EVM_WORD_WIDTH_IN_BYTES) {
+                offsetStr = `0x${(offset + j).toString(constants.HEX_BASE)}`.padEnd(offsetPadding);
                 valueStr = ethUtil
                     .stripHexPrefix(
-                        ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)),
+                        ethUtil.bufferToHex(block.toBuffer().slice(j, j + constants.EVM_WORD_WIDTH_IN_BYTES)),
                     )
                     .padEnd(valuePadding);
                 nameStr = ' '.repeat(namePadding);
diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
index fbe592fc7..189841989 100644
--- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -1,7 +1,7 @@
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 import { Queue } from '../utils/queue';
 
 export class RawCalldata {
@@ -24,8 +24,8 @@ export class RawCalldata {
         this._offset = RawCalldata._INITIAL_OFFSET;
         // If there's a selector then slice it
         if (hasSelector) {
-            const selectorBuf = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES);
-            this._value = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES);
+            const selectorBuf = this._value.slice(constants.HEX_SELECTOR_LENGTH_IN_BYTES);
+            this._value = this._value.slice(constants.HEX_SELECTOR_LENGTH_IN_BYTES);
             this._selector = ethUtil.bufferToHex(selectorBuf);
         }
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 07a0bd10c..c45355639 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -4,12 +4,12 @@ import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 export class Address extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
-    private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = Constants.EVM_WORD_WIDTH_IN_BYTES -
+    private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = constants.EVM_WORD_WIDTH_IN_BYTES -
     Address._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
@@ -30,7 +30,7 @@ export class Address extends AbstractDataTypes.Blob {
             throw new Error(`Invalid address: '${value}'`);
         }
         const valueBuf = ethUtil.toBuffer(value);
-        const encodedValueBuf = ethUtil.setLengthLeft(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const encodedValueBuf = ethUtil.setLengthLeft(valueBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
         return encodedValueBuf;
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index a86283c2a..272cc4132 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -2,7 +2,7 @@ import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 export class Array extends AbstractDataTypes.Set {
     private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$');
@@ -23,7 +23,7 @@ export class Array extends AbstractDataTypes.Set {
             throw new Error(`Could not parse array length: ${type}`);
         }
         const arrayElementType = matches[1];
-        const arrayLength = _.isEmpty(matches[2]) ? undefined : parseInt(matches[2], Constants.DEC_BASE);
+        const arrayLength = _.isEmpty(matches[2]) ? undefined : parseInt(matches[2], constants.DEC_BASE);
         return [arrayElementType, arrayLength];
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 7af13506b..0c29f690a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 export class Bool extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
@@ -27,7 +27,7 @@ export class Bool extends AbstractDataTypes.Blob {
         const encodedValue = value ? '0x1' : '0x0';
         const encodedValueBuf = ethUtil.setLengthLeft(
             ethUtil.toBuffer(encodedValue),
-            Constants.EVM_WORD_WIDTH_IN_BYTES,
+            constants.EVM_WORD_WIDTH_IN_BYTES,
         );
         return encodedValueBuf;
     }
@@ -35,7 +35,7 @@ export class Bool extends AbstractDataTypes.Blob {
     public decodeValue(calldata: RawCalldata): boolean {
         const valueBuf = calldata.popWord();
         const valueHex = ethUtil.bufferToHex(valueBuf);
-        const valueNumber = new BigNumber(valueHex, Constants.HEX_BASE);
+        const valueNumber = new BigNumber(valueHex, constants.HEX_BASE);
         if (!(valueNumber.equals(0) || valueNumber.equals(1))) {
             throw new Error(`Failed to decode boolean. Expected 0x0 or 0x1, got ${valueHex}`);
         }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index ac2a1fb6e..2c256cfa9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 export class DynamicBytes extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
@@ -37,10 +37,10 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
         // 1/3 Construct the length
         const valueBuf = ethUtil.toBuffer(value);
-        const wordsToStoreValuePadded = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const bytesToStoreValuePadded = wordsToStoreValuePadded * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const wordsToStoreValuePadded = Math.ceil(valueBuf.byteLength / constants.EVM_WORD_WIDTH_IN_BYTES);
+        const bytesToStoreValuePadded = wordsToStoreValuePadded * constants.EVM_WORD_WIDTH_IN_BYTES;
         const lengthBuf = ethUtil.toBuffer(valueBuf.byteLength);
-        const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
         // 2/3 Construct the value
         DynamicBytes._sanityCheckValue(value);
         const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
@@ -54,9 +54,9 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         // 1/2 Decode length
         const lengthBuf = calldata.popWord();
         const lengthHex = ethUtil.bufferToHex(lengthBuf);
-        const length = parseInt(lengthHex, Constants.HEX_BASE);
+        const length = parseInt(lengthHex, constants.HEX_BASE);
         // 2/2 Decode value
-        const wordsToStoreValuePadded = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const wordsToStoreValuePadded = Math.ceil(length / constants.EVM_WORD_WIDTH_IN_BYTES);
         const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
         const valueBuf = valueBufPadded.slice(0, length);
         const value = ethUtil.bufferToHex(valueBuf);
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 3e465fc15..244b720e3 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
 export class Int extends AbstractDataTypes.Blob {
@@ -26,7 +26,7 @@ export class Int extends AbstractDataTypes.Blob {
         const matches = Int._MATCHER.exec(type);
         const width =
             !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
-                ? parseInt(matches[1], Constants.DEC_BASE)
+                ? parseInt(matches[1], constants.DEC_BASE)
                 : Int._DEFAULT_WIDTH;
         return width;
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index bd4732097..7256a93d9 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -3,7 +3,7 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { Tuple } from './tuple';
@@ -62,7 +62,7 @@ export class Method extends AbstractDataTypes.Set {
             ethUtil.toBuffer(
                 ethUtil
                     .sha3(signature)
-                    .slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES),
+                    .slice(constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, constants.HEX_SELECTOR_LENGTH_IN_BYTES),
             ),
         );
         return selector;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index ed1f51f7e..5453d47a0 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 export class StaticBytes extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
@@ -22,7 +22,7 @@ export class StaticBytes extends AbstractDataTypes.Blob {
         const matches = StaticBytes._MATCHER.exec(type);
         const width =
             !_.isNull(matches) && matches.length === 3 && !_.isUndefined(matches[2])
-                ? parseInt(matches[2], Constants.DEC_BASE)
+                ? parseInt(matches[2], constants.DEC_BASE)
                 : StaticBytes._DEFAULT_WIDTH;
         return width;
     }
@@ -45,7 +45,7 @@ export class StaticBytes extends AbstractDataTypes.Blob {
         this._sanityCheckValue(value);
         const valueBuf = ethUtil.toBuffer(value);
         // 2/2 Store value as hex
-        const valuePadded = ethUtil.setLengthRight(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const valuePadded = ethUtil.setLengthRight(valueBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
         return valuePadded;
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index e5b2d5f33..ac62ea264 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 export class String extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
@@ -25,10 +25,10 @@ export class String extends AbstractDataTypes.Blob {
     public encodeValue(value: string): Buffer {
         // Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
         // 1/3 Construct the length
-        const wordsToStoreValuePadded = Math.ceil(value.length / Constants.EVM_WORD_WIDTH_IN_BYTES);
-        const bytesToStoreValuePadded = wordsToStoreValuePadded * Constants.EVM_WORD_WIDTH_IN_BYTES;
+        const wordsToStoreValuePadded = Math.ceil(value.length / constants.EVM_WORD_WIDTH_IN_BYTES);
+        const bytesToStoreValuePadded = wordsToStoreValuePadded * constants.EVM_WORD_WIDTH_IN_BYTES;
         const lengthBuf = ethUtil.toBuffer(value.length);
-        const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
         // 2/3 Construct the value
         const valueBuf = new Buffer(value);
         const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
@@ -42,9 +42,9 @@ export class String extends AbstractDataTypes.Blob {
         // 1/2 Decode length
         const lengthBufPadded = calldata.popWord();
         const lengthHexPadded = ethUtil.bufferToHex(lengthBufPadded);
-        const length = parseInt(lengthHexPadded, Constants.HEX_BASE);
+        const length = parseInt(lengthHexPadded, constants.HEX_BASE);
         // 2/2 Decode value
-        const wordsToStoreValuePadded = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
+        const wordsToStoreValuePadded = Math.ceil(length / constants.EVM_WORD_WIDTH_IN_BYTES);
         const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
         const valueBuf = valueBufPadded.slice(0, length);
         const value = valueBuf.toString('ascii');
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index 970400a57..df7ea38a4 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
 export class UInt extends AbstractDataTypes.Blob {
@@ -26,7 +26,7 @@ export class UInt extends AbstractDataTypes.Blob {
         const matches = UInt._MATCHER.exec(type);
         const width =
             !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
-                ? parseInt(matches[1], Constants.DEC_BASE)
+                ? parseInt(matches[1], constants.DEC_BASE)
                 : UInt._DEFAULT_WIDTH;
         return width;
     }
diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts
index 05c6783e7..82eeab010 100644
--- a/packages/utils/src/abi_encoder/utils/constants.ts
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -1,12 +1,14 @@
 import { DecodingRules, EncodingRules } from './rules';
 
-export const EVM_WORD_WIDTH_IN_BYTES = 32;
-export const EVM_WORD_WIDTH_IN_BITS = 256;
-export const HEX_BASE = 16;
-export const DEC_BASE = 10;
-export const BIN_BASE = 2;
-export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
-export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
-export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
-export const DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
-export const DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
+export const constants = {
+    EVM_WORD_WIDTH_IN_BYTES: 32,
+    EVM_WORD_WIDTH_IN_BITS: 256,
+    HEX_BASE: 16,
+    DEC_BASE: 10,
+    BIN_BASE: 2,
+    HEX_SELECTOR_LENGTH_IN_CHARS: 10,
+    HEX_SELECTOR_LENGTH_IN_BYTES: 4,
+    HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA: 0,
+    DEFAULT_DECODING_RULES: { structsAsObjects: false } as DecodingRules,
+    DEFAULT_ENCODING_RULES: { optimize: false, annotate: false } as EncodingRules,
+};
diff --git a/packages/utils/src/abi_encoder/utils/math.ts b/packages/utils/src/abi_encoder/utils/math.ts
index 9bcdc3af1..d84983c5b 100644
--- a/packages/utils/src/abi_encoder/utils/math.ts
+++ b/packages/utils/src/abi_encoder/utils/math.ts
@@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import * as Constants from '../utils/constants';
+import { constants } from '../utils/constants';
 
 function sanityCheckBigNumberRange(
     value_: BigNumber | string | number,
@@ -17,9 +17,9 @@ function sanityCheckBigNumberRange(
     }
 }
 function bigNumberToPaddedBuffer(value: BigNumber): Buffer {
-    const valueHex = `0x${value.toString(Constants.HEX_BASE)}`;
+    const valueHex = `0x${value.toString(constants.HEX_BASE)}`;
     const valueBuf = ethUtil.toBuffer(valueHex);
-    const valueBufPadded = ethUtil.setLengthLeft(valueBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
+    const valueBufPadded = ethUtil.setLengthLeft(valueBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
     return valueBufPadded;
 }
 /**
@@ -37,13 +37,13 @@ export function encodeNumericValue(value_: BigNumber | string | number): Buffer
     // Case 2/2: Value is negative
     // Use two's-complement to encode the value
     // Step 1/3: Convert negative value to positive binary string
-    const valueBin = value.times(-1).toString(Constants.BIN_BASE);
+    const valueBin = value.times(-1).toString(constants.BIN_BASE);
     // Step 2/3: Invert binary value
-    let invertedValueBin = '1'.repeat(Constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
+    let invertedValueBin = '1'.repeat(constants.EVM_WORD_WIDTH_IN_BITS - valueBin.length);
     _.each(valueBin, (bit: string) => {
         invertedValueBin += bit === '1' ? '0' : '1';
     });
-    const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
+    const invertedValue = new BigNumber(invertedValueBin, constants.BIN_BASE);
     // Step 3/3: Add 1 to inverted value
     const negativeValue = invertedValue.plus(1);
     const encodedValue = bigNumberToPaddedBuffer(negativeValue);
@@ -73,13 +73,13 @@ export function safeEncodeNumericValue(
 export function decodeNumericValue(encodedValue: Buffer, minValue: BigNumber): BigNumber {
     const valueHex = ethUtil.bufferToHex(encodedValue);
     // Case 1/3: value is definitely non-negative because of numeric boundaries
-    const value = new BigNumber(valueHex, Constants.HEX_BASE);
+    const value = new BigNumber(valueHex, constants.HEX_BASE);
     if (!minValue.lessThan(0)) {
         return value;
     }
     // Case 2/3: value is non-negative because there is no leading 1 (encoded as two's-complement)
-    const valueBin = value.toString(Constants.BIN_BASE);
-    const isValueNegative = valueBin.length === Constants.EVM_WORD_WIDTH_IN_BITS && _.startsWith(valueBin[0], '1');
+    const valueBin = value.toString(constants.BIN_BASE);
+    const isValueNegative = valueBin.length === constants.EVM_WORD_WIDTH_IN_BITS && _.startsWith(valueBin[0], '1');
     if (!isValueNegative) {
         return value;
     }
@@ -89,7 +89,7 @@ export function decodeNumericValue(encodedValue: Buffer, minValue: BigNumber): B
     _.each(valueBin, (bit: string) => {
         invertedValueBin += bit === '1' ? '0' : '1';
     });
-    const invertedValue = new BigNumber(invertedValueBin, Constants.BIN_BASE);
+    const invertedValue = new BigNumber(invertedValueBin, constants.BIN_BASE);
     // Step 2/3: Add 1 to inverted value
     // The result is the two's-complement representation of the input value.
     const positiveValue = invertedValue.plus(1);
-- 
cgit v1.2.3


From d6645b8a9116d92ac15f0b64f46566bf7f5447f1 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 17:23:01 -0800
Subject: Explicit encoding rules in tests.

---
 .../utils/test/abi_encoder/evm_data_types_test.ts  | 129 +++++++++++----------
 packages/utils/test/abi_encoder/methods_test.ts    |  37 +++---
 packages/utils/test/abi_encoder/optimizer_test.ts  |  31 ++---
 .../utils/test/abi_encoder/return_values_test.ts   |  11 +-
 4 files changed, 106 insertions(+), 102 deletions(-)

diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts
index 11cebda55..9ef80a560 100644
--- a/packages/utils/test/abi_encoder/evm_data_types_test.ts
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -10,6 +10,7 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
+    const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
     describe('Array', () => {
         it('Fixed size; Static elements', async () => {
             // Create DataType object
@@ -18,7 +19,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = [new BigNumber(5), new BigNumber(6)];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -33,7 +34,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = [new BigNumber(5), new BigNumber(6)];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -48,7 +49,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = ['Hello', 'world'];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -63,7 +64,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = ['Hello', 'world'];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -81,7 +82,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const array3 = ['0x18192021'];
             const args = [array1, array2, array3];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000041011121300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414151617000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -99,7 +100,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const array3 = ['0x18192021'];
             const args = [array1, array2, array3];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000301020304000000000000000000000000000000000000000000000000000000000506070800000000000000000000000000000000000000000000000000000000091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021011121300000000000000000000000000000000000000000000000000000000141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011819202100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -116,7 +117,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const array2 = ['0x10111213', '0x14151617', '0x18192021'];
             const args = [array1, array2];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x010203040000000000000000000000000000000000000000000000000000000005060708000000000000000000000000000000000000000000000000000000000910111200000000000000000000000000000000000000000000000000000000101112130000000000000000000000000000000000000000000000000000000014151617000000000000000000000000000000000000000000000000000000001819202100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -133,7 +134,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const array2 = ['0x10111213', '0x14151617', '0x18192021'];
             const args = [array1, array2];
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000401020304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040910111200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000410111213000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -149,7 +150,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = ['Hello', 'world'];
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw('Expected array of 3 elements, but got array of length 2');
         });
         it('Static size; Too Many Elements', async () => {
@@ -160,7 +161,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = ['Hello', 'world'];
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw('Expected array of 1 elements, but got array of length 2');
         });
         it('Element Type Mismatch', async () => {
@@ -171,7 +172,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = [new BigNumber(1), 'Bad Argument'];
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
     });
@@ -188,7 +189,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = { field_1: new BigNumber(-5), field_2: true };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -208,7 +209,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = { field_1: 'Hello, World!', field_2: '0xabcdef0123456789' };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -228,7 +229,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = { field: [new BigNumber(1), new BigNumber(2)] };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -248,7 +249,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = { field: [new BigNumber(1), new BigNumber(2)] };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -270,7 +271,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const array2 = ['0x09101112', '0x13141516'];
             const args = { field: [array1, array2] };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x0102030400000000000000000000000000000000000000000000000000000000050607080000000000000000000000000000000000000000000000000000000009101112000000000000000000000000000000000000000000000000000000001314151600000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -292,7 +293,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const array2 = ['0x09101112', '0x13141516'];
             const args = { field: [array1, array2] };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004010203040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040506070800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041314151600000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -322,7 +323,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
                 field_4: '0xabcdef0123456789',
             };
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008abcdef0123456789000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -343,7 +344,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = { field_1: new BigNumber(-5) };
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw('Could not assign tuple to object: missing keys field_2');
         });
         it('Bad Key', async () => {
@@ -358,7 +359,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = { unknown_field: new BigNumber(-5) };
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw("Could not assign tuple to object: unrecognized key 'unknown_field' in object Tuple");
         });
     });
@@ -371,7 +372,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = '0xe41d2489571d322189246dafa5ebde1f4699f498';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -386,7 +387,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = 'e4';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw(`Invalid address: '${args}'`);
         });
         it('Invalid Address - input is not 20 bytes', async () => {
@@ -397,7 +398,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '0xe4';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw(`Invalid address: '${args}'`);
         });
     });
@@ -410,7 +411,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = true;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -424,7 +425,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = false;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -448,7 +449,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = new BigNumber(1);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -462,7 +463,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = new BigNumber(-1);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -476,7 +477,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = max256BitInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -490,7 +491,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = min256BitInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = `0x8000000000000000000000000000000000000000000000000000000000000000`;
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -505,7 +506,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = max256BitInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
         it('Int256 - Value too small', async () => {
@@ -516,7 +517,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = min256BitInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
         it('Int32 - Positive Base Case', async () => {
@@ -526,7 +527,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = new BigNumber(1);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -540,7 +541,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = new BigNumber(-1);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -554,7 +555,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = max32BitInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000007fffffff';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -568,7 +569,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = min32BitInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000`;
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -583,7 +584,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = max32BitInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
         it('Int32 - Value too small', async () => {
@@ -594,7 +595,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = min32BitInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
     });
@@ -614,7 +615,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = new BigNumber(1);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -628,7 +629,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = max256BitUnsignedInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -642,7 +643,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = min256BitUnsignedInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -657,7 +658,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = max256BitUnsignedInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
         it('UInt256 - Value too small', async () => {
@@ -668,7 +669,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = min256BitUnsignedInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
         it('UInt32 - Positive Base Case', async () => {
@@ -678,7 +679,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = new BigNumber(1);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -692,7 +693,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = max32BitUnsignedInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000ffffffff';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -706,7 +707,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = min32BitUnsignedInteger;
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -721,7 +722,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = max32BitUnsignedInteger.plus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
         it('UInt32 - Value too small', async () => {
@@ -732,7 +733,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = min32BitUnsignedInteger.minus(1);
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw();
         });
     });
@@ -745,7 +746,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = '0x05';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -759,7 +760,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = '0x05';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -773,7 +774,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = '0x00010203';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0001020300000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -788,7 +789,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x1a18000000000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -803,7 +804,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Construct args to be encoded
             const args = '0x0001020304050607080911121314151617181920212223242526272829303132';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x0001020304050607080911121314151617181920212223242526272829303132';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -818,7 +819,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18bf61';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
             // Decode Encoded Args and validate result
@@ -834,7 +835,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '0x0102030405';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw(
                 'Tried to assign 0x0102030405 (5 bytes), which exceeds max bytes that can be stored in a bytes4',
             );
@@ -847,7 +848,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '0x010203040506070809101112131415161718192021222324252627282930313233';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw(
                 'Tried to assign 0x010203040506070809101112131415161718192021222324252627282930313233 (33 bytes), which exceeds max bytes that can be stored in a bytes32',
             );
@@ -860,7 +861,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '0102030405060708091011121314151617181920212223242526272829303132';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
         });
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
@@ -871,7 +872,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '0x010';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
         });
     });
@@ -885,7 +886,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = '0x1a18bf61';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -902,7 +903,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const bytesLength = 40;
             const args = '0x' + '61'.repeat(bytesLength);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -935,7 +936,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '01';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
         });
         it('Should throw when pass in bad hex (include a half-byte)', async () => {
@@ -946,7 +947,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const args = '0x010';
             // Encode Args and validate result
             expect(() => {
-                dataType.encode(args);
+                dataType.encode(args, encodingRules);
             }).to.throw('Tried to assign 0x010, which is contains a half-byte. Use full bytes only.');
         });
     });
@@ -960,7 +961,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             // Note: There will be padding because this is a bytes32 but we are only passing in 4 bytes.
             const args = 'five';
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -977,7 +978,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const bytesLength = 40;
             const args = 'a'.repeat(bytesLength);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
@@ -994,7 +995,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
             const strLength = 40;
             const args = '0x' + 'a'.repeat(strLength);
             // Encode Args and validate result
-            const encodedArgs = dataType.encode(args);
+            const encodedArgs = dataType.encode(args, encodingRules);
             const expectedEncodedArgs =
                 '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
             expect(encodedArgs).to.be.equal(expectedEncodedArgs);
diff --git a/packages/utils/test/abi_encoder/methods_test.ts b/packages/utils/test/abi_encoder/methods_test.ts
index c870f4f04..837020883 100644
--- a/packages/utils/test/abi_encoder/methods_test.ts
+++ b/packages/utils/test/abi_encoder/methods_test.ts
@@ -10,11 +10,12 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe('ABI Encoder: Method Encoding / Decoding', () => {
+    const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
     it('Types with default widths', async () => {
         // Generate calldata
         const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi);
         const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
@@ -33,7 +34,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
         }
         const args = [arrayOfTuples];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
@@ -52,7 +53,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]);
         }
         const args = [arrayOfTuples];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
@@ -71,7 +72,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
         }
         const args = [arrayOfTuples];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
@@ -90,7 +91,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]);
         }
         const args = [arrayOfTuples];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
@@ -112,7 +113,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
                 [[new BigNumber(++value), new BigNumber(++value)], [new BigNumber(++value), new BigNumber(++value)]],
             ]);
         }
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038';
@@ -141,7 +142,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
                 ],
             ]);
         }
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
@@ -154,7 +155,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // Generate calldata
         const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
         const args = [['Brave', 'New', 'World']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
@@ -167,7 +168,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // Generaet calldata
         const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi);
         const args = [['Brave', 'New', 'World']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
@@ -180,7 +181,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // Generate calldata
         const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi);
         const args = [['Brave', 'New', 'World']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
@@ -193,7 +194,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // Generate calldata
         const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi);
         const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
@@ -206,7 +207,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // Generate calldata
         const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi);
         const args = [[new BigNumber(127), new BigNumber(14), new BigNumber(54)]];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
@@ -219,7 +220,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // Generate calldata
         const method = new AbiEncoder.Method(AbiSamples.stringAbi);
         const args = [['five', 'six', 'seven']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
@@ -233,7 +234,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // This is dynamic because it has dynamic members
         const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi);
         const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
@@ -247,7 +248,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // This is dynamic because it has dynamic members
         const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
         const args = [[new BigNumber(5), 'five']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
@@ -261,7 +262,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
         // This is dynamic because it has dynamic members
         const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi);
         const args = [[new BigNumber(5), 'five']];
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
@@ -285,7 +286,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             true,
         ];
         // Validate calldata
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         const expectedCalldata =
             '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
         expect(calldata).to.be.equal(expectedCalldata);
@@ -353,7 +354,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => {
             someTupleWithDynamicTypes,
             someArrayOfTuplesWithDynamicTypes,
         };
-        const calldata = method.encode(args);
+        const calldata = method.encode(args, encodingRules);
         // Validate calldata
         const expectedCalldata =
             '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
diff --git a/packages/utils/test/abi_encoder/optimizer_test.ts b/packages/utils/test/abi_encoder/optimizer_test.ts
index 27443fe48..18aa6549a 100644
--- a/packages/utils/test/abi_encoder/optimizer_test.ts
+++ b/packages/utils/test/abi_encoder/optimizer_test.ts
@@ -10,6 +10,7 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
+    const encodingRules: AbiEncoder.EncodingRules = { optimize: true };
     it('Duplicate Dynamic Arrays with Static Elements', async () => {
         // Generate calldata
         const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements);
@@ -17,7 +18,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const array2 = array1;
         const args = [array1, array2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -32,7 +33,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const array2 = array1;
         const args = [array1, array2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -47,7 +48,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const array2 = array1;
         const args = [array1, array2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x7f8130430000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -64,7 +65,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const array2 = array1;
         const args = [array1, array2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -78,7 +79,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const strings = ['Hello', 'World', 'Hello', 'World'];
         const args = [strings];
         // Validate calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -92,7 +93,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const tuple = ['Hello', 'Hello'];
         const args = [tuple];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -109,7 +110,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const method = new AbiEncoder.Method(OptimizedAbis.duplicateStrings);
         const args = ['Hello', 'Hello'];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -127,7 +128,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const value = '0x01020304050607080910111213141516171819202122232425262728293031323334353637383940';
         const args = [value, value];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -142,7 +143,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const tuple2 = tuple1;
         const args = [tuple1, tuple2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -158,7 +159,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const tuple2 = [tuple1[0], new BigNumber(2)];
         const args = [tuple1, tuple2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -174,7 +175,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const tuple2 = [array, 'extra argument to prevent exactly matching the tuples'];
         const args = [tuple1, tuple2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -190,7 +191,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const tuple2 = [nestedTuple, 'extra argument to prevent exactly matching the tuples'];
         const args = [tuple1, tuple2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -220,7 +221,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const twoDimArray2 = [['Hello', 'World'], ['Bar']];
         const args = [twoDimArray1, twoDimArray2];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -235,7 +236,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const tuple = [[array[0]], [array[1]], [array[2]], [array[3]]];
         const args = [array, tuple];
         // Validata calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
@@ -250,7 +251,7 @@ describe('ABI Encoder: Optimized Method Encoding/Decoding', () => {
         const str = 'Hello';
         const args = [array, str];
         // Validate calldata
-        const optimizedCalldata = method.encode(args, { optimize: true });
+        const optimizedCalldata = method.encode(args, encodingRules);
         const expectedOptimizedCalldata =
             '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
         expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
diff --git a/packages/utils/test/abi_encoder/return_values_test.ts b/packages/utils/test/abi_encoder/return_values_test.ts
index 3215509f1..a8cdd6ca3 100644
--- a/packages/utils/test/abi_encoder/return_values_test.ts
+++ b/packages/utils/test/abi_encoder/return_values_test.ts
@@ -10,6 +10,7 @@ chaiSetup.configure();
 const expect = chai.expect;
 
 describe('ABI Encoder: Return Value Encoding/Decoding', () => {
+    const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
     it('No Return Value', async () => {
         // Decode return value
         const method = new AbiEncoder.Method(ReturnValueAbis.noReturnValues);
@@ -22,7 +23,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         // Generate Return Value
         const method = new AbiEncoder.Method(ReturnValueAbis.singleStaticReturnValue);
         const returnValue = ['0x01020304'];
-        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
         expect(decodedReturnValue).to.be.deep.equal(returnValue);
@@ -31,7 +32,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         // Generate Return Value
         const method = new AbiEncoder.Method(ReturnValueAbis.multipleStaticReturnValues);
         const returnValue = ['0x01020304', '0x05060708'];
-        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
         expect(decodedReturnValue).to.be.deep.equal(returnValue);
@@ -40,7 +41,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         // Generate Return Value
         const method = new AbiEncoder.Method(ReturnValueAbis.singleDynamicReturnValue);
         const returnValue = ['0x01020304'];
-        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
         expect(decodedReturnValue).to.be.deep.equal(returnValue);
@@ -49,7 +50,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         // Generate Return Value
         const method = new AbiEncoder.Method(ReturnValueAbis.multipleDynamicReturnValues);
         const returnValue = ['0x01020304', '0x05060708'];
-        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
         expect(decodedReturnValue).to.be.deep.equal(returnValue);
@@ -58,7 +59,7 @@ describe('ABI Encoder: Return Value Encoding/Decoding', () => {
         // Generate Return Value
         const method = new AbiEncoder.Method(ReturnValueAbis.mixedStaticAndDynamicReturnValues);
         const returnValue = ['0x01020304', '0x05060708'];
-        const encodedReturnValue = method.encodeReturnValues(returnValue);
+        const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
         const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
         // Validate decoded return value
         expect(decodedReturnValue).to.be.deep.equal(returnValue);
-- 
cgit v1.2.3


From 5c13353fb2512411c0f2c8cba9395235188f5df8 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Tue, 27 Nov 2018 17:24:14 -0800
Subject: Optimize calldata by default.

---
 packages/utils/src/abi_encoder/utils/constants.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts
index 82eeab010..acc06329c 100644
--- a/packages/utils/src/abi_encoder/utils/constants.ts
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -10,5 +10,5 @@ export const constants = {
     HEX_SELECTOR_LENGTH_IN_BYTES: 4,
     HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA: 0,
     DEFAULT_DECODING_RULES: { structsAsObjects: false } as DecodingRules,
-    DEFAULT_ENCODING_RULES: { optimize: false, annotate: false } as EncodingRules,
+    DEFAULT_ENCODING_RULES: { optimize: true, annotate: false } as EncodingRules,
 };
-- 
cgit v1.2.3


From a172ab158e2eaca8256ef881c3f2d4098987ec8a Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 13:22:18 -0800
Subject: Explicit imports for EVM Data Types

---
 .../utils/src/abi_encoder/evm_data_type_factory.ts | 38 ++++++++++++++--------
 .../src/abi_encoder/evm_data_types/address.ts      | 10 +++---
 .../utils/src/abi_encoder/evm_data_types/array.ts  |  8 ++---
 .../utils/src/abi_encoder/evm_data_types/bool.ts   |  6 ++--
 .../abi_encoder/evm_data_types/dynamic_bytes.ts    | 10 +++---
 .../utils/src/abi_encoder/evm_data_types/index.ts  | 11 -------
 .../utils/src/abi_encoder/evm_data_types/int.ts    | 16 ++++-----
 .../utils/src/abi_encoder/evm_data_types/method.ts |  6 ++--
 .../src/abi_encoder/evm_data_types/pointer.ts      |  2 +-
 .../src/abi_encoder/evm_data_types/static_bytes.ts | 14 ++++----
 .../utils/src/abi_encoder/evm_data_types/string.ts |  6 ++--
 .../utils/src/abi_encoder/evm_data_types/tuple.ts  |  4 +--
 .../utils/src/abi_encoder/evm_data_types/uint.ts   | 20 ++++++------
 packages/utils/src/abi_encoder/index.ts            | 14 +++++++-
 14 files changed, 88 insertions(+), 77 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/evm_data_types/index.ts

diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index bc68e05b7..4d04d4ed7 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -3,69 +3,79 @@ import { DataItem, MethodAbi } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { DataType, DataTypeFactory } from './abstract_data_types';
-import * as Impl from './evm_data_types';
-
-export class Address extends Impl.Address {
+import { AddressDataType } from './evm_data_types/address';
+import { ArrayDataType } from './evm_data_types/array';
+import { BoolDataType } from './evm_data_types/bool';
+import { DynamicBytesDataType } from './evm_data_types/dynamic_bytes';
+import { IntDataType } from './evm_data_types/int';
+import { MethodDataType } from './evm_data_types/method';
+import { PointerDataType } from './evm_data_types/pointer';
+import { StaticBytesDataType } from './evm_data_types/static_bytes';
+import { StringDataType } from './evm_data_types/string';
+import { TupleDataType } from './evm_data_types/tuple';
+import { UIntDataType } from './evm_data_types/uint';
+
+export class Address extends AddressDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class Bool extends Impl.Bool {
+export class Bool extends BoolDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class Int extends Impl.Int {
+export class Int extends IntDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class UInt extends Impl.UInt {
+export class UInt extends UIntDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class StaticBytes extends Impl.StaticBytes {
+export class StaticBytes extends StaticBytesDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class DynamicBytes extends Impl.DynamicBytes {
+export class DynamicBytes extends DynamicBytesDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class String extends Impl.String {
+export class String extends StringDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class Pointer extends Impl.Pointer {
+export class Pointer extends PointerDataType {
     public constructor(destDataType: DataType, parentDataType: DataType) {
         super(destDataType, parentDataType, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class Tuple extends Impl.Tuple {
+export class Tuple extends TupleDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class Array extends Impl.Array {
+export class Array extends ArrayDataType {
     public constructor(dataItem: DataItem) {
         super(dataItem, EvmDataTypeFactory.getInstance());
     }
 }
 
-export class Method extends Impl.Method {
+export class Method extends MethodDataType {
     public constructor(abi: MethodAbi) {
         super(abi, EvmDataTypeFactory.getInstance());
     }
@@ -105,7 +115,7 @@ export class EvmDataTypeFactory implements DataTypeFactory {
         } else if (String.matchType(dataItem.type)) {
             dataType = new String(dataItem);
         }
-        // @TODO: Implement Fixed/UFixed types
+        // @TODO: DataTypeement Fixed/UFixed types
         if (_.isUndefined(dataType)) {
             throw new Error(`Unrecognized data type: '${dataItem.type}'`);
         } else if (!_.isUndefined(parentDataType) && !dataType.isStatic()) {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index c45355639..769c5a81c 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -6,19 +6,19 @@ import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class Address extends AbstractDataTypes.Blob {
+export class AddressDataType extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = constants.EVM_WORD_WIDTH_IN_BYTES -
-    Address._ADDRESS_SIZE_IN_BYTES;
+    AddressDataType._ADDRESS_SIZE_IN_BYTES;
 
     public static matchType(type: string): boolean {
         return type === SolidityTypes.Address;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, Address._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Address.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, AddressDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!AddressDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Address with bad input: ${dataItem}`);
         }
     }
@@ -36,7 +36,7 @@ export class Address extends AbstractDataTypes.Blob {
 
     public decodeValue(calldata: RawCalldata): string {
         const valueBufPadded = calldata.popWord();
-        const valueBuf = valueBufPadded.slice(Address._DECODED_ADDRESS_OFFSET_IN_BYTES);
+        const valueBuf = valueBufPadded.slice(AddressDataType._DECODED_ADDRESS_OFFSET_IN_BYTES);
         const value = ethUtil.bufferToHex(valueBuf);
         return value;
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 272cc4132..1736bcef0 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -4,17 +4,17 @@ import * as _ from 'lodash';
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { constants } from '../utils/constants';
 
-export class Array extends AbstractDataTypes.Set {
+export class ArrayDataType extends AbstractDataTypes.Set {
     private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$');
     private readonly _arraySignature: string;
     private readonly _elementType: string;
 
     public static matchType(type: string): boolean {
-        return Array._MATCHER.test(type);
+        return ArrayDataType._MATCHER.test(type);
     }
 
     private static _decodeElementTypeAndLengthFromType(type: string): [string, undefined | number] {
-        const matches = Array._MATCHER.exec(type);
+        const matches = ArrayDataType._MATCHER.exec(type);
         if (_.isNull(matches) || matches.length !== 3) {
             throw new Error(`Could not parse array: ${type}`);
         } else if (_.isUndefined(matches[1])) {
@@ -30,7 +30,7 @@ export class Array extends AbstractDataTypes.Set {
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         // Construct parent
         const isArray = true;
-        const [arrayElementType, arrayLength] = Array._decodeElementTypeAndLengthFromType(dataItem.type);
+        const [arrayElementType, arrayLength] = ArrayDataType._decodeElementTypeAndLengthFromType(dataItem.type);
         super(dataItem, dataTypeFactory, isArray, arrayLength, arrayElementType);
         // Set array properties
         this._elementType = arrayElementType;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 0c29f690a..32eda9c39 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -7,7 +7,7 @@ import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class Bool extends AbstractDataTypes.Blob {
+export class BoolDataType extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
     public static matchType(type: string): boolean {
@@ -15,8 +15,8 @@ export class Bool extends AbstractDataTypes.Blob {
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, Bool._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Bool.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, BoolDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!BoolDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Bool with bad input: ${dataItem}`);
         }
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index 2c256cfa9..c8ff47c3d 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -6,7 +6,7 @@ import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class DynamicBytes extends AbstractDataTypes.Blob {
+export class DynamicBytesDataType extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
@@ -25,8 +25,8 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!DynamicBytes.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, DynamicBytesDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!DynamicBytesDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Dynamic Bytes with bad input: ${dataItem}`);
         }
     }
@@ -42,7 +42,7 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         const lengthBuf = ethUtil.toBuffer(valueBuf.byteLength);
         const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
         // 2/3 Construct the value
-        DynamicBytes._sanityCheckValue(value);
+        DynamicBytesDataType._sanityCheckValue(value);
         const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
         // 3/3 Combine length and value
         const encodedValue = Buffer.concat([lengthBufPadded, valueBufPadded]);
@@ -60,7 +60,7 @@ export class DynamicBytes extends AbstractDataTypes.Blob {
         const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
         const valueBuf = valueBufPadded.slice(0, length);
         const value = ethUtil.bufferToHex(valueBuf);
-        DynamicBytes._sanityCheckValue(value);
+        DynamicBytesDataType._sanityCheckValue(value);
         return value;
     }
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/index.ts b/packages/utils/src/abi_encoder/evm_data_types/index.ts
deleted file mode 100644
index fc0edabf1..000000000
--- a/packages/utils/src/abi_encoder/evm_data_types/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export * from './address';
-export * from './bool';
-export * from './int';
-export * from './uint';
-export * from './static_bytes';
-export * from './dynamic_bytes';
-export * from './string';
-export * from './pointer';
-export * from './tuple';
-export * from './array';
-export * from './method';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 244b720e3..aee8320a6 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -7,36 +7,36 @@ import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-export class Int extends AbstractDataTypes.Blob {
+export class IntDataType extends AbstractDataTypes.Blob {
     private static readonly _MATCHER = RegExp(
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MAX_WIDTH: number = 256;
-    private static readonly _DEFAULT_WIDTH: number = Int._MAX_WIDTH;
+    private static readonly _DEFAULT_WIDTH: number = IntDataType._MAX_WIDTH;
     private readonly _width: number;
     private readonly _minValue: BigNumber;
     private readonly _maxValue: BigNumber;
 
     public static matchType(type: string): boolean {
-        return Int._MATCHER.test(type);
+        return IntDataType._MATCHER.test(type);
     }
 
     private static _decodeWidthFromType(type: string): number {
-        const matches = Int._MATCHER.exec(type);
+        const matches = IntDataType._MATCHER.exec(type);
         const width =
             !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
                 ? parseInt(matches[1], constants.DEC_BASE)
-                : Int._DEFAULT_WIDTH;
+                : IntDataType._DEFAULT_WIDTH;
         return width;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, Int._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!Int.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, IntDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!IntDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Int with bad input: ${dataItem}`);
         }
-        this._width = Int._decodeWidthFromType(dataItem.type);
+        this._width = IntDataType._decodeWidthFromType(dataItem.type);
         this._minValue = new BigNumber(2).toPower(this._width - 1).times(-1);
         this._maxValue = new BigNumber(2).toPower(this._width - 1).sub(1);
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index 7256a93d9..de8809edf 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -6,9 +6,9 @@ import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_t
 import { constants } from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
-import { Tuple } from './tuple';
+import { TupleDataType } from './tuple';
 
-export class Method extends AbstractDataTypes.Set {
+export class MethodDataType extends AbstractDataTypes.Set {
     private readonly _methodSignature: string;
     private readonly _methodSelector: string;
     private readonly _returnDataType: DataType;
@@ -19,7 +19,7 @@ export class Method extends AbstractDataTypes.Set {
         this._methodSignature = this._computeSignature();
         this._methodSelector = this._computeSelector();
         const returnDataItem: DataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
-        this._returnDataType = new Tuple(returnDataItem, this.getFactory());
+        this._returnDataType = new TupleDataType(returnDataItem, this.getFactory());
     }
 
     public encode(value: any, rules?: EncodingRules): string {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
index e7c172afb..7ca428760 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -2,7 +2,7 @@ import { DataItem } from 'ethereum-types';
 
 import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types';
 
-export class Pointer extends AbstractDataTypes.Pointer {
+export class PointerDataType extends AbstractDataTypes.Pointer {
     constructor(destDataType: DataType, parentDataType: DataType, dataTypeFactory: DataTypeFactory) {
         const destDataItem = destDataType.getDataItem();
         const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` };
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 5453d47a0..3b270630e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -6,7 +6,7 @@ import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class StaticBytes extends AbstractDataTypes.Blob {
+export class StaticBytesDataType extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MATCHER = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
@@ -15,24 +15,24 @@ export class StaticBytes extends AbstractDataTypes.Blob {
     private readonly _width: number;
 
     public static matchType(type: string): boolean {
-        return StaticBytes._MATCHER.test(type);
+        return StaticBytesDataType._MATCHER.test(type);
     }
 
     private static _decodeWidthFromType(type: string): number {
-        const matches = StaticBytes._MATCHER.exec(type);
+        const matches = StaticBytesDataType._MATCHER.exec(type);
         const width =
             !_.isNull(matches) && matches.length === 3 && !_.isUndefined(matches[2])
                 ? parseInt(matches[2], constants.DEC_BASE)
-                : StaticBytes._DEFAULT_WIDTH;
+                : StaticBytesDataType._DEFAULT_WIDTH;
         return width;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, StaticBytes._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!StaticBytes.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, StaticBytesDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!StaticBytesDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Static Bytes with bad input: ${dataItem}`);
         }
-        this._width = StaticBytes._decodeWidthFromType(dataItem.type);
+        this._width = StaticBytesDataType._decodeWidthFromType(dataItem.type);
     }
 
     public getSignature(): string {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index ac62ea264..d7e9ec7fe 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -6,7 +6,7 @@ import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class String extends AbstractDataTypes.Blob {
+export class StringDataType extends AbstractDataTypes.Blob {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
@@ -14,8 +14,8 @@ export class String extends AbstractDataTypes.Blob {
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, String._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!String.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, StringDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!StringDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate String with bad input: ${dataItem}`);
         }
     }
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 40859f62e..5ba875b9e 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -2,7 +2,7 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 
 import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
 
-export class Tuple extends AbstractDataTypes.Set {
+export class TupleDataType extends AbstractDataTypes.Set {
     private readonly _signature: string;
 
     public static matchType(type: string): boolean {
@@ -11,7 +11,7 @@ export class Tuple extends AbstractDataTypes.Set {
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
         super(dataItem, dataTypeFactory);
-        if (!Tuple.matchType(dataItem.type)) {
+        if (!TupleDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
         }
         this._signature = this._computeSignatureOfMembers();
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index df7ea38a4..a5989ea11 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -7,47 +7,47 @@ import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-export class UInt extends AbstractDataTypes.Blob {
+export class UIntDataType extends AbstractDataTypes.Blob {
     private static readonly _MATCHER = RegExp(
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MAX_WIDTH: number = 256;
-    private static readonly _DEFAULT_WIDTH: number = UInt._MAX_WIDTH;
+    private static readonly _DEFAULT_WIDTH: number = UIntDataType._MAX_WIDTH;
     private static readonly _MIN_VALUE = new BigNumber(0);
     private readonly _width: number;
     private readonly _maxValue: BigNumber;
 
     public static matchType(type: string): boolean {
-        return UInt._MATCHER.test(type);
+        return UIntDataType._MATCHER.test(type);
     }
 
     private static _decodeWidthFromType(type: string): number {
-        const matches = UInt._MATCHER.exec(type);
+        const matches = UIntDataType._MATCHER.exec(type);
         const width =
             !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
                 ? parseInt(matches[1], constants.DEC_BASE)
-                : UInt._DEFAULT_WIDTH;
+                : UIntDataType._DEFAULT_WIDTH;
         return width;
     }
 
     public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
-        super(dataItem, dataTypeFactory, UInt._SIZE_KNOWN_AT_COMPILE_TIME);
-        if (!UInt.matchType(dataItem.type)) {
+        super(dataItem, dataTypeFactory, UIntDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+        if (!UIntDataType.matchType(dataItem.type)) {
             throw new Error(`Tried to instantiate UInt with bad input: ${dataItem}`);
         }
-        this._width = UInt._decodeWidthFromType(dataItem.type);
+        this._width = UIntDataType._decodeWidthFromType(dataItem.type);
         this._maxValue = new BigNumber(2).toPower(this._width).sub(1);
     }
 
     public encodeValue(value: BigNumber | string | number): Buffer {
-        const encodedValue = EncoderMath.safeEncodeNumericValue(value, UInt._MIN_VALUE, this._maxValue);
+        const encodedValue = EncoderMath.safeEncodeNumericValue(value, UIntDataType._MIN_VALUE, this._maxValue);
         return encodedValue;
     }
 
     public decodeValue(calldata: RawCalldata): BigNumber {
         const valueBuf = calldata.popWord();
-        const value = EncoderMath.safeDecodeNumericValue(valueBuf, UInt._MIN_VALUE, this._maxValue);
+        const value = EncoderMath.safeDecodeNumericValue(valueBuf, UIntDataType._MIN_VALUE, this._maxValue);
         return value;
     }
 
diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts
index ea037b40a..baf844ac6 100644
--- a/packages/utils/src/abi_encoder/index.ts
+++ b/packages/utils/src/abi_encoder/index.ts
@@ -1,2 +1,14 @@
 export { EncodingRules, DecodingRules } from './utils/rules';
-export * from './evm_data_type_factory';
+export {
+    Address,
+    Array,
+    Bool,
+    DynamicBytes,
+    Int,
+    Method,
+    Pointer,
+    StaticBytes,
+    String,
+    Tuple,
+    UInt,
+} from './evm_data_type_factory';
-- 
cgit v1.2.3


From b8ea322541e291b84f261bffcc77baf85dae08c1 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 13:35:53 -0800
Subject: Explicit imports for abstract data types.

---
 packages/utils/src/abi_encoder/abstract_data_types/index.ts         | 4 ----
 packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts    | 2 +-
 packages/utils/src/abi_encoder/abstract_data_types/types/index.ts   | 3 ---
 packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts | 2 +-
 packages/utils/src/abi_encoder/abstract_data_types/types/set.ts     | 6 +++---
 packages/utils/src/abi_encoder/evm_data_type_factory.ts             | 3 ++-
 packages/utils/src/abi_encoder/evm_data_types/address.ts            | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/array.ts              | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/bool.ts               | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts      | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/int.ts                | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/method.ts             | 6 ++++--
 packages/utils/src/abi_encoder/evm_data_types/pointer.ts            | 6 ++++--
 packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts       | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/string.ts             | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/tuple.ts              | 5 +++--
 packages/utils/src/abi_encoder/evm_data_types/uint.ts               | 5 +++--
 17 files changed, 42 insertions(+), 35 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/index.ts
 delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/index.ts

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/index.ts
deleted file mode 100644
index d1c7d93e4..000000000
--- a/packages/utils/src/abi_encoder/abstract_data_types/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export * from './interfaces';
-export * from './data_type';
-import * as AbstractDataTypes from './types';
-export { AbstractDataTypes };
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
index 965738056..cd2119673 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -7,7 +7,7 @@ import { DecodingRules } from '../../utils/rules';
 import { DataType } from '../data_type';
 import { DataTypeFactory } from '../interfaces';
 
-export abstract class Blob extends DataType {
+export abstract class AbstractBlobDataType extends DataType {
     protected _sizeKnownAtCompileTime: boolean;
 
     public constructor(dataItem: DataItem, factory: DataTypeFactory, sizeKnownAtCompileTime: boolean) {
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts
deleted file mode 100644
index 958582dae..000000000
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './blob';
-export * from './pointer';
-export * from './set';
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index 3d38deb94..b6a6a7613 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -9,7 +9,7 @@ import { DecodingRules } from '../../utils/rules';
 import { DataType } from '../data_type';
 import { DataTypeFactory } from '../interfaces';
 
-export abstract class Pointer extends DataType {
+export abstract class AbstractPointerDataType extends DataType {
     protected _destination: DataType;
     protected _parent: DataType;
 
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index f50ed8298..4c8bb7b1a 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -10,9 +10,9 @@ import { DecodingRules } from '../../utils/rules';
 import { DataType } from '../data_type';
 import { DataTypeFactory, MemberIndexByName } from '../interfaces';
 
-import { Pointer } from './pointer';
+import { AbstractPointerDataType } from './pointer';
 
-export abstract class Set extends DataType {
+export abstract class AbstractSetDataType extends DataType {
     protected readonly _arrayLength: number | undefined;
     protected readonly _arrayElementType: string | undefined;
     private readonly _memberIndexByName: MemberIndexByName;
@@ -88,7 +88,7 @@ export abstract class Set extends DataType {
         }
         // If any member of the set is a pointer then the set is not static.
         const dependentMember = _.find(this._members, (member: DataType) => {
-            return member instanceof Pointer;
+            return member instanceof AbstractPointerDataType;
         });
         const isStatic = _.isUndefined(dependentMember);
         return isStatic;
diff --git a/packages/utils/src/abi_encoder/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
index 4d04d4ed7..4cc124e0a 100644
--- a/packages/utils/src/abi_encoder/evm_data_type_factory.ts
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -2,7 +2,8 @@
 import { DataItem, MethodAbi } from 'ethereum-types';
 import * as _ from 'lodash';
 
-import { DataType, DataTypeFactory } from './abstract_data_types';
+import { DataType } from './abstract_data_types/data_type';
+import { DataTypeFactory } from './abstract_data_types/interfaces';
 import { AddressDataType } from './evm_data_types/address';
 import { ArrayDataType } from './evm_data_types/array';
 import { BoolDataType } from './evm_data_types/bool';
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 769c5a81c..17363b5f3 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -2,11 +2,12 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class AddressDataType extends AbstractDataTypes.Blob {
+export class AddressDataType extends AbstractBlobDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _ADDRESS_SIZE_IN_BYTES = 20;
     private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = constants.EVM_WORD_WIDTH_IN_BYTES -
diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts
index 1736bcef0..7595cb667 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/array.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -1,10 +1,11 @@
 import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractSetDataType } from '../abstract_data_types/types/set';
 import { constants } from '../utils/constants';
 
-export class ArrayDataType extends AbstractDataTypes.Set {
+export class ArrayDataType extends AbstractSetDataType {
     private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$');
     private readonly _arraySignature: string;
     private readonly _elementType: string;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 32eda9c39..778a01d8a 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -3,11 +3,12 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class BoolDataType extends AbstractDataTypes.Blob {
+export class BoolDataType extends AbstractBlobDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index c8ff47c3d..ac8e2b716 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -2,11 +2,12 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class DynamicBytesDataType extends AbstractDataTypes.Blob {
+export class DynamicBytesDataType extends AbstractBlobDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index aee8320a6..6b5c3bf78 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -2,12 +2,13 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-export class IntDataType extends AbstractDataTypes.Blob {
+export class IntDataType extends AbstractBlobDataType {
     private static readonly _MATCHER = RegExp(
         '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts
index de8809edf..b1cd1377f 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/method.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -2,13 +2,15 @@ import { DataItem, MethodAbi } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types';
+import { DataType } from '../abstract_data_types/data_type';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractSetDataType } from '../abstract_data_types/types/set';
 import { constants } from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
 import { TupleDataType } from './tuple';
 
-export class MethodDataType extends AbstractDataTypes.Set {
+export class MethodDataType extends AbstractSetDataType {
     private readonly _methodSignature: string;
     private readonly _methodSelector: string;
     private readonly _returnDataType: DataType;
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
index 7ca428760..389e75927 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -1,8 +1,10 @@
 import { DataItem } from 'ethereum-types';
 
-import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types';
+import { DataType } from '../abstract_data_types/data_type';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractPointerDataType } from '../abstract_data_types/types/pointer';
 
-export class PointerDataType extends AbstractDataTypes.Pointer {
+export class PointerDataType extends AbstractPointerDataType {
     constructor(destDataType: DataType, parentDataType: DataType, dataTypeFactory: DataTypeFactory) {
         const destDataItem = destDataType.getDataItem();
         const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` };
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 3b270630e..28584d445 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -2,11 +2,12 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class StaticBytesDataType extends AbstractDataTypes.Blob {
+export class StaticBytesDataType extends AbstractBlobDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
     private static readonly _MATCHER = RegExp(
         '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$',
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index d7e9ec7fe..7b6af747b 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -2,11 +2,12 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 
-export class StringDataType extends AbstractDataTypes.Blob {
+export class StringDataType extends AbstractBlobDataType {
     private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
index 5ba875b9e..31593c882 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -1,8 +1,9 @@
 import { DataItem, SolidityTypes } from 'ethereum-types';
 
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractSetDataType } from '../abstract_data_types/types/set';
 
-export class TupleDataType extends AbstractDataTypes.Set {
+export class TupleDataType extends AbstractSetDataType {
     private readonly _signature: string;
 
     public static matchType(type: string): boolean {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index a5989ea11..45cb366f7 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -2,12 +2,13 @@ import { DataItem, SolidityTypes } from 'ethereum-types';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../configured_bignumber';
-import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types';
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
 import { RawCalldata } from '../calldata';
 import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-export class UIntDataType extends AbstractDataTypes.Blob {
+export class UIntDataType extends AbstractBlobDataType {
     private static readonly _MATCHER = RegExp(
         '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$',
     );
-- 
cgit v1.2.3


From 2da7cadefa877ff824da8fbaecd59dbff5028728 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 13:47:01 -0800
Subject: Explicit imports for calldata

---
 .../utils/src/abi_encoder/abstract_data_types/data_type.ts |  4 +++-
 .../src/abi_encoder/abstract_data_types/interfaces.ts      |  2 +-
 .../src/abi_encoder/abstract_data_types/types/blob.ts      |  8 +++++---
 .../src/abi_encoder/abstract_data_types/types/pointer.ts   |  8 +++++---
 .../utils/src/abi_encoder/abstract_data_types/types/set.ts | 14 ++++++++------
 packages/utils/src/abi_encoder/calldata/blocks/blob.ts     |  2 +-
 packages/utils/src/abi_encoder/calldata/blocks/index.ts    |  3 ---
 packages/utils/src/abi_encoder/calldata/blocks/pointer.ts  | 10 +++++-----
 packages/utils/src/abi_encoder/calldata/blocks/set.ts      |  2 +-
 packages/utils/src/abi_encoder/calldata/calldata.ts        |  7 ++++---
 packages/utils/src/abi_encoder/calldata/index.ts           |  5 -----
 packages/utils/src/abi_encoder/calldata/iterator.ts        | 10 ++++++----
 packages/utils/src/abi_encoder/evm_data_types/address.ts   |  2 +-
 packages/utils/src/abi_encoder/evm_data_types/bool.ts      |  2 +-
 .../utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts  |  2 +-
 packages/utils/src/abi_encoder/evm_data_types/int.ts       |  2 +-
 .../utils/src/abi_encoder/evm_data_types/static_bytes.ts   |  2 +-
 packages/utils/src/abi_encoder/evm_data_types/string.ts    |  2 +-
 packages/utils/src/abi_encoder/evm_data_types/uint.ts      |  2 +-
 19 files changed, 46 insertions(+), 43 deletions(-)
 delete mode 100644 packages/utils/src/abi_encoder/calldata/blocks/index.ts
 delete mode 100644 packages/utils/src/abi_encoder/calldata/index.ts

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
index 10e5c2540..13cc87e2a 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -1,7 +1,9 @@
 import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
-import { Calldata, CalldataBlock, RawCalldata } from '../calldata';
+import { Calldata } from '../calldata/calldata';
+import { CalldataBlock } from '../calldata/calldata_block';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 import { DecodingRules, EncodingRules } from '../utils/rules';
 
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
index bd4d2effd..2f2f60871 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
@@ -1,6 +1,6 @@
 import { DataItem } from 'ethereum-types';
 
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 
 import { DataType } from './data_type';
 
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
index cd2119673..a091e55b9 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -1,7 +1,9 @@
 import { DataItem } from 'ethereum-types';
 import * as _ from 'lodash';
 
-import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
+import { BlobCalldataBlock } from '../../calldata/blocks/blob';
+import { CalldataBlock } from '../../calldata/calldata_block';
+import { RawCalldata } from '../../calldata/raw_calldata';
 import { DecodingRules } from '../../utils/rules';
 
 import { DataType } from '../data_type';
@@ -15,12 +17,12 @@ export abstract class AbstractBlobDataType extends DataType {
         this._sizeKnownAtCompileTime = sizeKnownAtCompileTime;
     }
 
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Blob {
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): BlobCalldataBlock {
         const encodedValue = this.encodeValue(value);
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
-        const block = new CalldataBlocks.Blob(name, signature, parentName, encodedValue);
+        const block = new BlobCalldataBlock(name, signature, parentName, encodedValue);
         return block;
     }
 
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index b6a6a7613..0f3c55280 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -2,7 +2,9 @@ import { DataItem } from 'ethereum-types';
 import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
-import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
+import { PointerCalldataBlock } from '../../calldata/blocks/pointer';
+import { CalldataBlock } from '../../calldata/calldata_block';
+import { RawCalldata } from '../../calldata/raw_calldata';
 import { constants } from '../../utils/constants';
 import { DecodingRules } from '../../utils/rules';
 
@@ -19,7 +21,7 @@ export abstract class AbstractPointerDataType extends DataType {
         this._parent = parent;
     }
 
-    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Pointer {
+    public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PointerCalldataBlock {
         if (_.isUndefined(parentBlock)) {
             throw new Error(`DependentDataType requires a parent block to generate its block`);
         }
@@ -27,7 +29,7 @@ export abstract class AbstractPointerDataType extends DataType {
         const name = this.getDataItem().name;
         const signature = this.getSignature();
         const parentName = parentBlock.getName();
-        const block = new CalldataBlocks.Pointer(name, signature, parentName, destinationBlock, parentBlock);
+        const block = new PointerCalldataBlock(name, signature, parentName, destinationBlock, parentBlock);
         return block;
     }
 
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 4c8bb7b1a..bbe29eff0 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -3,7 +3,9 @@ import * as ethUtil from 'ethereumjs-util';
 import * as _ from 'lodash';
 
 import { BigNumber } from '../../../configured_bignumber';
-import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata';
+import { SetCalldataBlock } from '../../calldata/blocks/set';
+import { CalldataBlock } from '../../calldata/calldata_block';
+import { RawCalldata } from '../../calldata/raw_calldata';
 import { constants } from '../../utils/constants';
 import { DecodingRules } from '../../utils/rules';
 
@@ -39,7 +41,7 @@ export abstract class AbstractSetDataType extends DataType {
         }
     }
 
-    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
+    public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): SetCalldataBlock {
         const block =
             value instanceof Array
                 ? this._generateCalldataBlockFromArray(value, parentBlock)
@@ -94,7 +96,7 @@ export abstract class AbstractSetDataType extends DataType {
         return isStatic;
     }
 
-    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): CalldataBlocks.Set {
+    protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): SetCalldataBlock {
         // Sanity check: if the set has a defined length then `value` must have the same length.
         if (!_.isUndefined(this._arrayLength) && value.length !== this._arrayLength) {
             throw new Error(
@@ -105,7 +107,7 @@ export abstract class AbstractSetDataType extends DataType {
         }
         // Create a new calldata block for this set.
         const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
-        const block: CalldataBlocks.Set = new CalldataBlocks.Set(
+        const block = new SetCalldataBlock(
             this.getDataItem().name,
             this.getSignature(),
             parentName,
@@ -130,10 +132,10 @@ export abstract class AbstractSetDataType extends DataType {
         return block;
     }
 
-    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
+    protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): SetCalldataBlock {
         // Create a new calldata block for this set.
         const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
-        const block: CalldataBlocks.Set = new CalldataBlocks.Set(
+        const block = new SetCalldataBlock(
             this.getDataItem().name,
             this.getSignature(),
             parentName,
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts
index 210ef6420..219ea6c61 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts
@@ -1,6 +1,6 @@
 import { CalldataBlock } from '../calldata_block';
 
-export class Blob extends CalldataBlock {
+export class BlobCalldataBlock extends CalldataBlock {
     private readonly _blob: Buffer;
 
     constructor(name: string, signature: string, parentName: string, blob: Buffer) {
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/index.ts b/packages/utils/src/abi_encoder/calldata/blocks/index.ts
deleted file mode 100644
index 958582dae..000000000
--- a/packages/utils/src/abi_encoder/calldata/blocks/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './blob';
-export * from './pointer';
-export * from './set';
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
index 1daf33f7e..c706fe908 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
@@ -5,7 +5,7 @@ import { constants } from '../../utils/constants';
 
 import { CalldataBlock } from '../calldata_block';
 
-export class Pointer extends CalldataBlock {
+export class PointerCalldataBlock extends CalldataBlock {
     public static readonly RAW_DATA_START = new Buffer('<');
     public static readonly RAW_DATA_END = new Buffer('>');
     private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32;
@@ -15,8 +15,8 @@ export class Pointer extends CalldataBlock {
     private _aliasFor: CalldataBlock | undefined;
 
     constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) {
-        const headerSizeInBytes = Pointer._EMPTY_HEADER_SIZE;
-        const bodySizeInBytes = Pointer._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
+        const headerSizeInBytes = PointerCalldataBlock._EMPTY_HEADER_SIZE;
+        const bodySizeInBytes = PointerCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES;
         super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes);
         this._parent = parent;
         this._dependency = dependency;
@@ -51,9 +51,9 @@ export class Pointer extends CalldataBlock {
     public getRawData(): Buffer {
         const dependencyRawData = this._dependency.getRawData();
         const rawDataComponents: Buffer[] = [];
-        rawDataComponents.push(Pointer.RAW_DATA_START);
+        rawDataComponents.push(PointerCalldataBlock.RAW_DATA_START);
         rawDataComponents.push(dependencyRawData);
-        rawDataComponents.push(Pointer.RAW_DATA_END);
+        rawDataComponents.push(PointerCalldataBlock.RAW_DATA_END);
         const rawData = Buffer.concat(rawDataComponents);
         return rawData;
     }
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts
index 81455b364..d1abc4986 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/set.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts
@@ -2,7 +2,7 @@ import * as _ from 'lodash';
 
 import { CalldataBlock } from '../calldata_block';
 
-export class Set extends CalldataBlock {
+export class SetCalldataBlock extends CalldataBlock {
     private _header: Buffer | undefined;
     private _members: CalldataBlock[];
 
diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts
index e5858b524..5f3eee94a 100644
--- a/packages/utils/src/abi_encoder/calldata/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -4,7 +4,8 @@ import * as _ from 'lodash';
 import { constants } from '../utils/constants';
 import { EncodingRules } from '../utils/rules';
 
-import * as CalldataBlocks from './blocks';
+import { PointerCalldataBlock } from './blocks/pointer';
+import { SetCalldataBlock } from './blocks/set';
 import { CalldataBlock } from './calldata_block';
 import { CalldataIterator, ReverseCalldataIterator } from './iterator';
 
@@ -112,7 +113,7 @@ export class Calldata {
         for (const block of iterator) {
             // If a block is a pointer and its value has already been observed, then update
             // the pointer to resolve to the existing value.
-            if (block instanceof CalldataBlocks.Pointer) {
+            if (block instanceof PointerCalldataBlock) {
                 const dependencyBlockHashBuf = block.getDependency().computeHash();
                 const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf);
                 if (dependencyBlockHash in blocksByHash) {
@@ -214,7 +215,7 @@ export class Calldata {
                         ),
                     )
                     .padEnd(valuePadding);
-                if (block instanceof CalldataBlocks.Set) {
+                if (block instanceof SetCalldataBlock) {
                     nameStr = `### ${prettyName.padEnd(namePadding)}`;
                     lineStr = `\n${offsetStr}${valueStr}${nameStr}`;
                 } else {
diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts
deleted file mode 100644
index 2ef75e8d0..000000000
--- a/packages/utils/src/abi_encoder/calldata/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './calldata';
-export * from './calldata_block';
-export * from './raw_calldata';
-import * as CalldataBlocks from './blocks';
-export { CalldataBlocks };
diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts
index 5307f7944..333b32b4f 100644
--- a/packages/utils/src/abi_encoder/calldata/iterator.ts
+++ b/packages/utils/src/abi_encoder/calldata/iterator.ts
@@ -3,7 +3,9 @@ import * as _ from 'lodash';
 
 import { Queue } from '../utils/queue';
 
-import * as CalldataBlocks from './blocks';
+import { BlobCalldataBlock } from './blocks/blob';
+import { PointerCalldataBlock } from './blocks/pointer';
+import { SetCalldataBlock } from './blocks/set';
 import { CalldataBlock } from './calldata_block';
 
 /**
@@ -42,7 +44,7 @@ abstract class BaseIterator implements Iterable<CalldataBlock> {
     private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
         const queue = new Queue<CalldataBlock>();
         // Base case
-        if (!(block instanceof CalldataBlocks.Set)) {
+        if (!(block instanceof SetCalldataBlock)) {
             queue.pushBack(block);
             return queue;
         }
@@ -55,7 +57,7 @@ abstract class BaseIterator implements Iterable<CalldataBlock> {
         _.each(set.getMembers(), (member: CalldataBlock) => {
             // Traverse child if it is a unique pointer.
             // A pointer that is an alias for another pointer is ignored.
-            if (member instanceof CalldataBlocks.Pointer && _.isUndefined(member.getAlias())) {
+            if (member instanceof PointerCalldataBlock && _.isUndefined(member.getAlias())) {
                 const dependency = member.getDependency();
                 queue.mergeBack(BaseIterator._createQueue(dependency));
             }
@@ -82,7 +84,7 @@ abstract class BaseIterator implements Iterable<CalldataBlock> {
                 }
                 return {
                     done: true,
-                    value: new CalldataBlocks.Blob('', '', '', new Buffer('')),
+                    value: new BlobCalldataBlock('', '', '', new Buffer('')),
                 };
             },
         };
diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts
index 17363b5f3..88846b1fa 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/address.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 
 export class AddressDataType extends AbstractBlobDataType {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
index 778a01d8a..d713d5a94 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -5,7 +5,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 
 export class BoolDataType extends AbstractBlobDataType {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
index ac8e2b716..5277efd6c 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 
 export class DynamicBytesDataType extends AbstractBlobDataType {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts
index 6b5c3bf78..f1dcf5ea1 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/int.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
index 28584d445..2e371c505 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 
 export class StaticBytesDataType extends AbstractBlobDataType {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts
index 7b6af747b..91a72ad3f 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/string.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 
 export class StringDataType extends AbstractBlobDataType {
diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
index 45cb366f7..5180f0cf3 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
 import { BigNumber } from '../../configured_bignumber';
 import { DataTypeFactory } from '../abstract_data_types/interfaces';
 import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
-import { RawCalldata } from '../calldata';
+import { RawCalldata } from '../calldata/raw_calldata';
 import { constants } from '../utils/constants';
 import * as EncoderMath from '../utils/math';
 
-- 
cgit v1.2.3


From 04503200e5eafda6617039b113ef26cf48184f62 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 13:52:32 -0800
Subject: Linter / Prettier

---
 .../src/abi_encoder/abstract_data_types/types/set.ts   | 18 +++++++-----------
 .../utils/src/abi_encoder/calldata/blocks/pointer.ts   |  5 +++--
 packages/utils/src/abi_encoder/utils/constants.ts      |  3 +++
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index bbe29eff0..089d04659 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -107,11 +107,7 @@ export abstract class AbstractSetDataType extends DataType {
         }
         // Create a new calldata block for this set.
         const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
-        const block = new SetCalldataBlock(
-            this.getDataItem().name,
-            this.getSignature(),
-            parentName,
-        );
+        const block = new SetCalldataBlock(this.getDataItem().name, this.getSignature(), parentName);
         // If this set has an undefined length then set its header to be the number of elements.
         let members = this._members;
         if (this._isArray && _.isUndefined(this._arrayLength)) {
@@ -135,11 +131,7 @@ export abstract class AbstractSetDataType extends DataType {
     protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): SetCalldataBlock {
         // Create a new calldata block for this set.
         const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
-        const block = new SetCalldataBlock(
-            this.getDataItem().name,
-            this.getSignature(),
-            parentName,
-        );
+        const block = new SetCalldataBlock(this.getDataItem().name, this.getSignature(), parentName);
         // Create blocks for members of set.
         const memberCalldataBlocks: CalldataBlock[] = [];
         const childMap = _.cloneDeep(this._memberIndexByName);
@@ -178,7 +170,11 @@ export abstract class AbstractSetDataType extends DataType {
     private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] {
         // Sanity check
         if (_.isUndefined(dataItem.components)) {
-            throw new Error(`Tried to create a set using key/value pairs, but no components were defined by the input DataItem '${dataItem.name}'.`);
+            throw new Error(
+                `Tried to create a set using key/value pairs, but no components were defined by the input DataItem '${
+                    dataItem.name
+                }'.`,
+            );
         }
         // Create one member for each component of `dataItem`
         const members: DataType[] = [];
diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
index c706fe908..72d6a3173 100644
--- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
+++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
@@ -24,8 +24,9 @@ export class PointerCalldataBlock extends CalldataBlock {
     }
 
     public toBuffer(): Buffer {
-        const destinationOffset =
-            !_.isUndefined(this._aliasFor) ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes();
+        const destinationOffset = !_.isUndefined(this._aliasFor)
+            ? this._aliasFor.getOffsetInBytes()
+            : this._dependency.getOffsetInBytes();
         const parentOffset = this._parent.getOffsetInBytes();
         const parentHeaderSize = this._parent.getHeaderSizeInBytes();
         const pointer: number = destinationOffset - (parentOffset + parentHeaderSize);
diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts
index acc06329c..2f43ba04d 100644
--- a/packages/utils/src/abi_encoder/utils/constants.ts
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -9,6 +9,9 @@ export const constants = {
     HEX_SELECTOR_LENGTH_IN_CHARS: 10,
     HEX_SELECTOR_LENGTH_IN_BYTES: 4,
     HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA: 0,
+    // Disable no-object-literal-type-assertion so we can enforce cast
+    /* tslint:disable no-object-literal-type-assertion */
     DEFAULT_DECODING_RULES: { structsAsObjects: false } as DecodingRules,
     DEFAULT_ENCODING_RULES: { optimize: true, annotate: false } as EncodingRules,
+    /* tslint:enable no-object-literal-type-assertion */
 };
-- 
cgit v1.2.3


From b15531fe683df906b4988e63bbca2b3ebfbfc6b2 Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 15:50:36 -0800
Subject: Changelog for ABI Encoder

---
 packages/utils/CHANGELOG.json | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index 8c6fb124f..bbaf67062 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -1,4 +1,13 @@
 [
+    {
+        "timestamp": 1543448882,
+        "version": "2.0.7",
+        "changes": [
+            {
+                "note": "Optimized ABI Encoder/Decoder. Generates compressed calldata to save gas. Generates human-readable calldata to aid development."
+            }
+        ]
+    },
     {
         "timestamp": 1542821676,
         "version": "2.0.6",
-- 
cgit v1.2.3


From bcb2af2861952c91ea4fc02462f52d8bc37bac5d Mon Sep 17 00:00:00 2001
From: Greg Hysen <greg.hysen@gmail.com>
Date: Wed, 28 Nov 2018 17:30:02 -0800
Subject: Ran prettier

---
 packages/utils/CHANGELOG.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index bbaf67062..08801a891 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -4,7 +4,8 @@
         "version": "2.0.7",
         "changes": [
             {
-                "note": "Optimized ABI Encoder/Decoder. Generates compressed calldata to save gas. Generates human-readable calldata to aid development."
+                "note":
+                    "Optimized ABI Encoder/Decoder. Generates compressed calldata to save gas. Generates human-readable calldata to aid development."
             }
         ]
     },
-- 
cgit v1.2.3


From 5c66f9117fa0bf6a5be29243dbecbfe016b95345 Mon Sep 17 00:00:00 2001
From: Steve Klebanoff <steve.klebanoff@gmail.com>
Date: Thu, 29 Nov 2018 08:19:39 -0800
Subject: assetAmount -> assetBuyAmount

---
 packages/instant/src/util/analytics.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
index 1468ef4a8..4b8aff4c9 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -206,10 +206,10 @@ export const analytics = {
             ...buyQuoteEventProperties(buyQuote),
             fetchOrigin,
         }),
-    trackQuoteError: (errorMessage: string, assetAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => {
+    trackQuoteError: (errorMessage: string, assetBuyAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => {
         trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({
             errorMessage,
-            assetAmount: assetAmount.toString(),
+            assetBuyAmount: assetBuyAmount.toString(),
             fetchOrigin,
         });
     },
-- 
cgit v1.2.3


From b68273e592dc7736d21608e2543ba6bffdb03db2 Mon Sep 17 00:00:00 2001
From: Fabio Berger <me@fabioberger.com>
Date: Thu, 29 Nov 2018 17:30:21 +0000
Subject: Fix import export so that it works with doc gen

---
 packages/utils/src/index.ts | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index f59cbec8c..082aff6bb 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -10,5 +10,4 @@ export { NULL_BYTES } from './constants';
 export { errorUtils } from './error_utils';
 export { fetchAsync } from './fetch_async';
 export { signTypedDataUtils } from './sign_typed_data_utils';
-import * as AbiEncoder from './abi_encoder';
-export { AbiEncoder };
+export import AbiEncoder = require('./abi_encoder');
-- 
cgit v1.2.3


From a1d4aa66bc6b3de041ec6e4eb4fe40383945510b Mon Sep 17 00:00:00 2001
From: Daniel Pyrathon <pirosb3@gmail.com>
Date: Fri, 30 Nov 2018 09:59:37 -0800
Subject: feat(order_utils.py): schema resolver cache (#1317)

* Implemented basic functionality for using cache layer of LocalRefResolver

* Use `importlib` instead of `imp`, since it's been deprecated. Legacy `load_module()` reloads modules even if they are already imported, causing tests to fail when run in non-deterministic ordering, so we replace it with `import_module()`
---
 .../src/zero_ex/json_schemas/__init__.py           | 81 +++++++++++++---------
 .../order_utils/stubs/jsonschema/__init__.pyi      | 10 ++-
 python-packages/order_utils/test/test_doctest.py   |  5 +-
 .../order_utils/test/test_json_schemas.py          | 23 ++++++
 4 files changed, 81 insertions(+), 38 deletions(-)
 create mode 100644 python-packages/order_utils/test/test_json_schemas.py

diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py b/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py
index 2a1728b8a..a76a2fa3b 100644
--- a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py
+++ b/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py
@@ -8,6 +8,51 @@ from pkg_resources import resource_string
 import jsonschema
 
 
+class _LocalRefResolver(jsonschema.RefResolver):
+    """Resolve package-local JSON schema id's."""
+
+    def __init__(self):
+        """Initialize a new instance."""
+        self.ref_to_file = {
+            "/addressSchema": "address_schema.json",
+            "/hexSchema": "hex_schema.json",
+            "/orderSchema": "order_schema.json",
+            "/wholeNumberSchema": "whole_number_schema.json",
+            "/ECSignature": "ec_signature_schema.json",
+            "/signedOrderSchema": "signed_order_schema.json",
+            "/ecSignatureParameterSchema": (
+                "ec_signature_parameter_schema.json" + ""
+            ),
+        }
+        jsonschema.RefResolver.__init__(self, "", "")
+
+    def resolve_from_url(self, url: str) -> str:
+        """Resolve the given URL.
+
+        :param url: a string representing the URL of the JSON schema to fetch.
+        :returns: a string representing the deserialized JSON schema
+        :raises jsonschema.ValidationError: when the resource associated with
+                   `url` does not exist.
+        """
+        ref = url.replace("file://", "")
+        if ref in self.ref_to_file:
+            return json.loads(
+                resource_string(
+                    "zero_ex.json_schemas", f"schemas/{self.ref_to_file[ref]}"
+                )
+            )
+        raise jsonschema.ValidationError(
+            f"Unknown ref '{ref}'. "
+            + f"Known refs: {list(self.ref_to_file.keys())}."
+        )
+
+
+# Instantiate the `_LocalRefResolver()` only once so that `assert_valid()` can
+# perform multiple schema validations without reading from disk the schema
+# every time.
+_LOCAL_RESOLVER = _LocalRefResolver()
+
+
 def assert_valid(data: Mapping, schema_id: str) -> None:
     """Validate the given `data` against the specified `schema`.
 
@@ -24,38 +69,6 @@ def assert_valid(data: Mapping, schema_id: str) -> None:
     ... )
     """
     # noqa
-    class LocalRefResolver(jsonschema.RefResolver):
-        """Resolve package-local JSON schema id's."""
-
-        def __init__(self):
-            self.ref_to_file = {
-                "/addressSchema": "address_schema.json",
-                "/hexSchema": "hex_schema.json",
-                "/orderSchema": "order_schema.json",
-                "/wholeNumberSchema": "whole_number_schema.json",
-                "/ECSignature": "ec_signature_schema.json",
-                "/ecSignatureParameterSchema": (
-                    "ec_signature_parameter_schema.json" + ""
-                ),
-            }
-            jsonschema.RefResolver.__init__(self, "", "")
-
-        def resolve_from_url(self, url):
-            """Resolve the given URL."""
-            ref = url.replace("file://", "")
-            if ref in self.ref_to_file:
-                return json.loads(
-                    resource_string(
-                        "zero_ex.json_schemas",
-                        f"schemas/{self.ref_to_file[ref]}",
-                    )
-                )
-            raise jsonschema.ValidationError(
-                f"Unknown ref '{ref}'. "
-                + f"Known refs: {list(self.ref_to_file.keys())}."
-            )
 
-    resolver = LocalRefResolver()
-    jsonschema.validate(
-        data, resolver.resolve_from_url(schema_id), resolver=resolver
-    )
+    _, schema = _LOCAL_RESOLVER.resolve(schema_id)
+    jsonschema.validate(data, schema, resolver=_LOCAL_RESOLVER)
diff --git a/python-packages/order_utils/stubs/jsonschema/__init__.pyi b/python-packages/order_utils/stubs/jsonschema/__init__.pyi
index 762b58b22..442e2f65e 100644
--- a/python-packages/order_utils/stubs/jsonschema/__init__.pyi
+++ b/python-packages/order_utils/stubs/jsonschema/__init__.pyi
@@ -1,5 +1,11 @@
-from typing import Any, Dict
+from typing import Any, Dict, Tuple
 
-class RefResolver: pass
+
+class RefResolver:
+    def resolve(self, url: str) -> Tuple[str, Dict]:
+        ...
+
+
+class ValidationError(Exception): pass
 
 def validate(instance: Any, schema: Dict, cls=None, *args, **kwargs) -> None: pass
diff --git a/python-packages/order_utils/test/test_doctest.py b/python-packages/order_utils/test/test_doctest.py
index f692b3b6c..297f75e75 100644
--- a/python-packages/order_utils/test/test_doctest.py
+++ b/python-packages/order_utils/test/test_doctest.py
@@ -2,16 +2,17 @@
 
 from doctest import testmod
 import pkgutil
+import importlib
 
 import zero_ex
 
 
 def test_all_doctests():
     """Gather zero_ex.* modules and doctest them."""
-    for (importer, modname, _) in pkgutil.walk_packages(
+    for (_, modname, _) in pkgutil.walk_packages(
         path=zero_ex.__path__, prefix="zero_ex."
     ):
-        module = importer.find_module(modname).load_module(modname)
+        module = importlib.import_module(modname)
         print(module)
         (failure_count, _) = testmod(module)
         assert failure_count == 0
diff --git a/python-packages/order_utils/test/test_json_schemas.py b/python-packages/order_utils/test/test_json_schemas.py
new file mode 100644
index 000000000..51cecbd4f
--- /dev/null
+++ b/python-packages/order_utils/test/test_json_schemas.py
@@ -0,0 +1,23 @@
+"""Tests of zero_ex.json_schemas"""
+
+
+from zero_ex.order_utils import make_empty_order
+from zero_ex.json_schemas import _LOCAL_RESOLVER, assert_valid
+
+
+def test_assert_valid_caches_resources():
+    """Test that the JSON ref resolver in `assert_valid()` caches resources
+
+    In order to test the cache we much access the private class of
+    `json_schemas` and reset the LRU cache on `_LocalRefResolver`.
+    For this to happen, we need to disable errror `W0212`
+    on _LOCAL_RESOLVER
+    """
+    _LOCAL_RESOLVER._remote_cache.cache_clear()  # pylint: disable=W0212
+
+    assert_valid(make_empty_order(), "/orderSchema")
+    cache_info = (
+        _LOCAL_RESOLVER._remote_cache.cache_info()  # pylint: disable=W0212
+    )
+    assert cache_info.currsize == 4
+    assert cache_info.hits == 10
-- 
cgit v1.2.3