aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/0x.js/.npmignore2
-rw-r--r--packages/0x.js/CHANGELOG.json9
-rw-r--r--packages/0x.js/CHANGELOG.md4
-rw-r--r--packages/0x.js/package.json22
-rw-r--r--packages/abi-gen-templates/CHANGELOG.json9
-rw-r--r--packages/abi-gen-templates/CHANGELOG.md14
-rw-r--r--packages/abi-gen-templates/package.json2
-rw-r--r--packages/abi-gen-wrappers/CHANGELOG.json3
-rw-r--r--packages/abi-gen-wrappers/CHANGELOG.md4
-rw-r--r--packages/abi-gen-wrappers/package.json8
-rw-r--r--packages/abi-gen/README.md4
-rw-r--r--packages/asset-buyer/CHANGELOG.json17
-rw-r--r--packages/asset-buyer/CHANGELOG.md4
-rw-r--r--packages/asset-buyer/package.json12
-rw-r--r--packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts8
-rw-r--r--packages/base-contract/CHANGELOG.json9
-rw-r--r--packages/base-contract/CHANGELOG.md4
-rw-r--r--packages/base-contract/package.json4
-rw-r--r--packages/connect/CHANGELOG.json9
-rw-r--r--packages/connect/CHANGELOG.md4
-rw-r--r--packages/connect/package.json4
-rw-r--r--packages/contract-addresses/CHANGELOG.json14
-rw-r--r--packages/contract-addresses/CHANGELOG.md5
-rw-r--r--packages/contract-addresses/package.json2
-rw-r--r--packages/contract-addresses/src/index.ts26
-rw-r--r--packages/contract-artifacts/CHANGELOG.json3
-rw-r--r--packages/contract-artifacts/CHANGELOG.md4
-rw-r--r--packages/contract-artifacts/package.json2
-rw-r--r--packages/contract-wrappers/.npmignore2
-rw-r--r--packages/contract-wrappers/CHANGELOG.json9
-rw-r--r--packages/contract-wrappers/CHANGELOG.md4
-rw-r--r--packages/contract-wrappers/package.json20
-rw-r--r--packages/contracts/.solhint.json20
-rw-r--r--packages/contracts/.solhintignore3
-rw-r--r--packages/contracts/CHANGELOG.json125
-rw-r--r--packages/contracts/README.md129
-rw-r--r--packages/contracts/compiler.json59
-rw-r--r--packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol100
-rw-r--r--packages/contracts/contracts/examples/Validator/Validator.sol56
-rw-r--r--packages/contracts/contracts/examples/Wallet/Wallet.sol65
-rw-r--r--packages/contracts/contracts/examples/Whitelist/Whitelist.sol136
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/Forwarder.sol50
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol143
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol260
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol214
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol113
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol34
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol30
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol80
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol62
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol34
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol53
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol87
-rw-r--r--packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol41
-rw-r--r--packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol218
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWallet.sol393
-rw-r--r--packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol127
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol184
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol171
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol117
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol40
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol46
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol52
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol38
-rw-r--r--packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol41
-rw-r--r--packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol108
-rw-r--r--packages/contracts/contracts/protocol/Exchange/Exchange.sol53
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol174
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol529
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol335
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol324
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol152
-rw-r--r--packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol426
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol37
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol38
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol60
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol44
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol57
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol35
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol37
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol35
-rw-r--r--packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol160
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol215
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol49
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol87
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol70
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol53
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol253
-rw-r--r--packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol145
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol45
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol157
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol58
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol75
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol58
-rw-r--r--packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol41
-rw-r--r--packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol77
-rw-r--r--packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol69
-rw-r--r--packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol115
-rw-r--r--packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol67
-rw-r--r--packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol66
-rw-r--r--packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol63
-rw-r--r--packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol188
-rw-r--r--packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol37
-rw-r--r--packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol58
-rw-r--r--packages/contracts/contracts/test/TestConstants/TestConstants.sol57
-rw-r--r--packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol191
-rw-r--r--packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol269
-rw-r--r--packages/contracts/contracts/test/TestLibs/TestLibs.sol152
-rw-r--r--packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol45
-rw-r--r--packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol81
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol148
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol87
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol60
-rw-r--r--packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol70
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol277
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol44
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol158
-rw-r--r--packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol82
-rw-r--r--packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol33
-rw-r--r--packages/contracts/contracts/tokens/EtherToken/WETH9.sol758
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol44
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol39
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol52
-rw-r--r--packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol41
-rw-r--r--packages/contracts/contracts/utils/LibBytes/LibBytes.sol567
-rw-r--r--packages/contracts/contracts/utils/Ownable/IOwnable.sol8
-rw-r--r--packages/contracts/contracts/utils/Ownable/Ownable.sol33
-rw-r--r--packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol45
-rw-r--r--packages/contracts/contracts/utils/SafeMath/SafeMath.sol87
-rw-r--r--packages/contracts/package.json92
-rw-r--r--packages/contracts/src/artifacts/index.ts79
-rw-r--r--packages/contracts/src/wrappers/index.ts34
-rw-r--r--packages/contracts/test/asset_proxy/authorizable.ts207
-rw-r--r--packages/contracts/test/asset_proxy/proxies.ts629
-rw-r--r--packages/contracts/test/exchange/core.ts829
-rw-r--r--packages/contracts/test/exchange/dispatcher.ts280
-rw-r--r--packages/contracts/test/exchange/fill_order.ts312
-rw-r--r--packages/contracts/test/exchange/internal.ts466
-rw-r--r--packages/contracts/test/exchange/libs.ts137
-rw-r--r--packages/contracts/test/exchange/match_orders.ts1276
-rw-r--r--packages/contracts/test/exchange/signature_validator.ts522
-rw-r--r--packages/contracts/test/exchange/transactions.ts462
-rw-r--r--packages/contracts/test/exchange/wrapper.ts1452
-rw-r--r--packages/contracts/test/extensions/forwarder.ts1282
-rw-r--r--packages/contracts/test/extensions/order_validator.ts603
-rw-r--r--packages/contracts/test/global_hooks.ts15
-rw-r--r--packages/contracts/test/libraries/lib_bytes.ts871
-rw-r--r--packages/contracts/test/multisig/asset_proxy_owner.ts498
-rw-r--r--packages/contracts/test/multisig/multi_sig_with_time_lock.ts347
-rw-r--r--packages/contracts/test/tokens/erc721_token.ts279
-rw-r--r--packages/contracts/test/tokens/unlimited_allowance_token.ts191
-rw-r--r--packages/contracts/test/tokens/weth9.ts138
-rw-r--r--packages/contracts/test/tokens/zrx_token.ts206
-rw-r--r--packages/contracts/test/tutorials/arbitrage.ts260
-rw-r--r--packages/contracts/test/utils/abstract_asset_wrapper.ts3
-rw-r--r--packages/contracts/test/utils/address_utils.ts11
-rw-r--r--packages/contracts/test/utils/assertions.ts199
-rw-r--r--packages/contracts/test/utils/asset_wrapper.ts223
-rw-r--r--packages/contracts/test/utils/block_timestamp.ts43
-rw-r--r--packages/contracts/test/utils/combinatorial_utils.ts113
-rw-r--r--packages/contracts/test/utils/constants.ts67
-rw-r--r--packages/contracts/test/utils/coverage.ts21
-rw-r--r--packages/contracts/test/utils/erc20_wrapper.ts182
-rw-r--r--packages/contracts/test/utils/erc721_wrapper.ts237
-rw-r--r--packages/contracts/test/utils/exchange_wrapper.ts276
-rw-r--r--packages/contracts/test/utils/fill_order_combinatorial_utils.ts924
-rw-r--r--packages/contracts/test/utils/formatters.ts68
-rw-r--r--packages/contracts/test/utils/forwarder_wrapper.ts121
-rw-r--r--packages/contracts/test/utils/log_decoder.ts53
-rw-r--r--packages/contracts/test/utils/match_order_tester.ts566
-rw-r--r--packages/contracts/test/utils/multi_sig_wrapper.ts67
-rw-r--r--packages/contracts/test/utils/order_factory.ts38
-rw-r--r--packages/contracts/test/utils/order_factory_from_scenario.ts296
-rw-r--r--packages/contracts/test/utils/order_utils.ts58
-rw-r--r--packages/contracts/test/utils/profiler.ts27
-rw-r--r--packages/contracts/test/utils/revert_trace.ts21
-rw-r--r--packages/contracts/test/utils/signing_utils.ts29
-rw-r--r--packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts19
-rw-r--r--packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts31
-rw-r--r--packages/contracts/test/utils/test_with_reference.ts139
-rw-r--r--packages/contracts/test/utils/transaction_factory.ts37
-rw-r--r--packages/contracts/test/utils/type_encoding_utils.ts21
-rw-r--r--packages/contracts/test/utils/types.ts241
-rw-r--r--packages/contracts/test/utils/web3_wrapper.ts84
-rw-r--r--packages/contracts/test/utils_test/test_with_reference.ts63
-rw-r--r--packages/contracts/tsconfig.json48
-rw-r--r--packages/contracts/tslint.json6
-rw-r--r--packages/dev-tools-pages/package.json4
-rw-r--r--packages/dev-utils/CHANGELOG.json9
-rw-r--r--packages/dev-utils/CHANGELOG.md4
-rw-r--r--packages/dev-utils/README.md15
-rw-r--r--packages/dev-utils/package.json6
-rw-r--r--packages/ethereum-types/src/index.ts5
-rw-r--r--packages/fill-scenarios/CHANGELOG.json9
-rw-r--r--packages/fill-scenarios/CHANGELOG.md4
-rw-r--r--packages/fill-scenarios/package.json12
-rw-r--r--packages/instant/.DS_Storebin0 -> 8196 bytes
-rw-r--r--packages/instant/.dogfood.discharge.json4
-rw-r--r--packages/instant/.env_example7
-rw-r--r--packages/instant/.gitignore3
-rw-r--r--packages/instant/.npmignore3
-rw-r--r--packages/instant/.production.discharge.json13
-rw-r--r--packages/instant/.staging.discharge.json4
-rw-r--r--packages/instant/README.md52
-rw-r--r--packages/instant/package.json26
-rw-r--r--packages/instant/public/index.html1
-rw-r--r--packages/instant/src/assets/icons/zrx.svg7
-rw-r--r--packages/instant/src/components/buy_button.tsx20
-rw-r--r--packages/instant/src/components/buy_order_progress.tsx2
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx4
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx8
-rw-r--r--packages/instant/src/components/erc20_token_selector.tsx10
-rw-r--r--packages/instant/src/components/install_wallet_panel_content.tsx9
-rw-r--r--packages/instant/src/components/instant_heading.tsx13
-rw-r--r--packages/instant/src/components/order_details.tsx2
-rw-r--r--packages/instant/src/components/payment_method.tsx23
-rw-r--r--packages/instant/src/components/payment_method_dropdown.tsx16
-rw-r--r--packages/instant/src/components/scaling_amount_input.tsx5
-rw-r--r--packages/instant/src/components/scaling_input.tsx6
-rw-r--r--packages/instant/src/components/search_input.tsx8
-rw-r--r--packages/instant/src/components/standard_panel_content.tsx13
-rw-r--r--packages/instant/src/components/standard_sliding_panel.tsx2
-rw-r--r--packages/instant/src/components/timed_progress_bar.tsx17
-rw-r--r--packages/instant/src/components/ui/container.tsx16
-rw-r--r--packages/instant/src/components/ui/dropdown.tsx8
-rw-r--r--packages/instant/src/components/ui/input.tsx1
-rw-r--r--packages/instant/src/components/ui/overlay.tsx2
-rw-r--r--packages/instant/src/components/ui/text.tsx6
-rw-r--r--packages/instant/src/components/wallet_prompt.tsx4
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx25
-rw-r--r--packages/instant/src/components/zero_ex_instant_overlay.tsx17
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx11
-rw-r--r--packages/instant/src/constants.ts23
-rw-r--r--packages/instant/src/containers/connected_account_payment_method.ts41
-rw-r--r--packages/instant/src/containers/latest_error.tsx8
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts8
-rw-r--r--packages/instant/src/containers/selected_erc20_asset_amount_input.ts4
-rw-r--r--packages/instant/src/data/asset_meta_data_map.ts6
-rw-r--r--packages/instant/src/index.umd.ts27
-rw-r--r--packages/instant/src/redux/analytics_middleware.ts52
-rw-r--r--packages/instant/src/redux/async_data.ts17
-rw-r--r--packages/instant/src/redux/reducer.ts1
-rw-r--r--packages/instant/src/style/theme.ts16
-rw-r--r--packages/instant/src/types.ts10
-rw-r--r--packages/instant/src/util/analytics.ts154
-rw-r--r--packages/instant/src/util/asset.ts17
-rw-r--r--packages/instant/src/util/buy_quote_updater.ts43
-rw-r--r--packages/instant/src/util/error_reporter.ts62
-rw-r--r--packages/instant/src/util/gas_price_estimator.ts5
-rw-r--r--packages/instant/src/util/heap.ts3
-rw-r--r--packages/instant/src/util/heartbeater_factory.ts12
-rw-r--r--packages/instant/test/util/asset.test.ts33
-rw-r--r--packages/instant/tsconfig.json8
-rw-r--r--packages/instant/webpack.config.js137
-rw-r--r--packages/metacoin/package.json16
-rw-r--r--packages/migrations/CHANGELOG.json3
-rw-r--r--packages/migrations/CHANGELOG.md6
-rw-r--r--packages/migrations/package.json20
-rw-r--r--packages/monorepo-scripts/CHANGELOG.json4
-rw-r--r--packages/monorepo-scripts/src/prepublish_checks.ts11
-rw-r--r--packages/monorepo-scripts/src/utils/github_release_utils.ts12
-rw-r--r--packages/order-utils/CHANGELOG.json9
-rw-r--r--packages/order-utils/CHANGELOG.md4
-rw-r--r--packages/order-utils/package.json12
-rw-r--r--packages/order-watcher/CHANGELOG.json9
-rw-r--r--packages/order-watcher/CHANGELOG.md4
-rw-r--r--packages/order-watcher/package.json22
-rw-r--r--packages/react-docs/CHANGELOG.json9
-rw-r--r--packages/react-docs/CHANGELOG.md4
-rw-r--r--packages/react-docs/package.json6
-rw-r--r--packages/react-shared/CHANGELOG.json9
-rw-r--r--packages/react-shared/CHANGELOG.md4
-rw-r--r--packages/react-shared/package.json4
-rw-r--r--packages/sol-compiler/CHANGELOG.json18
-rw-r--r--packages/sol-compiler/CHANGELOG.md4
-rw-r--r--packages/sol-compiler/package.json6
-rw-r--r--packages/sol-compiler/src/compiler.ts9
-rw-r--r--packages/sol-cov/CHANGELOG.json9
-rw-r--r--packages/sol-cov/CHANGELOG.md4
-rw-r--r--packages/sol-cov/package.json10
-rw-r--r--packages/sol-doc/CHANGELOG.json9
-rw-r--r--packages/sol-doc/CHANGELOG.md4
-rw-r--r--packages/sol-doc/package.json4
-rw-r--r--packages/sol-resolver/CHANGELOG.json9
-rw-r--r--packages/sol-resolver/src/resolvers/npm_resolver.ts15
-rw-r--r--packages/subproviders/CHANGELOG.json9
-rw-r--r--packages/subproviders/CHANGELOG.md4
-rw-r--r--packages/subproviders/package.json4
-rw-r--r--packages/testnet-faucets/package.json8
-rw-r--r--packages/types/CHANGELOG.json13
-rw-r--r--packages/types/src/index.ts8
-rw-r--r--packages/utils/CHANGELOG.json10
-rw-r--r--packages/utils/package.json5
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/data_type.ts58
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts19
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts40
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts54
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/set.ts218
-rw-r--r--packages/utils/src/abi_encoder/calldata/blocks/blob.ts20
-rw-r--r--packages/utils/src/abi_encoder/calldata/blocks/pointer.ts61
-rw-r--r--packages/utils/src/abi_encoder/calldata/blocks/set.ts47
-rw-r--r--packages/utils/src/abi_encoder/calldata/calldata.ts243
-rw-r--r--packages/utils/src/abi_encoder/calldata/calldata_block.ts77
-rw-r--r--packages/utils/src/abi_encoder/calldata/iterator.ts114
-rw-r--r--packages/utils/src/abi_encoder/calldata/raw_calldata.ts82
-rw-r--r--packages/utils/src/abi_encoder/evm_data_type_factory.ts132
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/address.ts49
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/array.ts64
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/bool.ts53
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts72
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/int.ts59
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/method.ts72
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/pointer.ts17
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts78
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/string.ts59
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/tuple.ts24
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/uint.ts58
-rw-r--r--packages/utils/src/abi_encoder/index.ts14
-rw-r--r--packages/utils/src/abi_encoder/utils/constants.ts17
-rw-r--r--packages/utils/src/abi_encoder/utils/math.ts111
-rw-r--r--packages/utils/src/abi_encoder/utils/queue.ts39
-rw-r--r--packages/utils/src/abi_encoder/utils/rules.ts8
-rw-r--r--packages/utils/src/index.ts1
-rw-r--r--packages/utils/test/abi_encoder/abi_samples/method_abis.ts780
-rw-r--r--packages/utils/test/abi_encoder/abi_samples/optimizer_abis.ts340
-rw-r--r--packages/utils/test/abi_encoder/abi_samples/return_value_abis.ts99
-rw-r--r--packages/utils/test/abi_encoder/evm_data_types_test.ts1007
-rw-r--r--packages/utils/test/abi_encoder/methods_test.ts366
-rw-r--r--packages/utils/test/abi_encoder/optimizer_test.ts262
-rw-r--r--packages/utils/test/abi_encoder/return_values_test.ts67
-rw-r--r--packages/utils/test/utils/chai_setup.ts (renamed from packages/contracts/test/utils/chai_setup.ts)0
-rw-r--r--packages/web3-wrapper/CHANGELOG.json3
-rw-r--r--packages/web3-wrapper/CHANGELOG.md4
-rw-r--r--packages/web3-wrapper/package.json2
-rw-r--r--packages/website/md/docs/smart_contracts/1/introduction.md2
-rw-r--r--packages/website/md/docs/smart_contracts/2/introduction.md2
-rw-r--r--packages/website/package.json14
-rw-r--r--packages/website/public/images/instant/dai_screenshot.pngbin0 -> 105373 bytes
-rw-r--r--packages/website/public/images/instant/feature_1.svg33
-rw-r--r--packages/website/public/images/instant/feature_2.svg15
-rw-r--r--packages/website/public/images/instant/feature_3.svg195
-rw-r--r--packages/website/public/images/instant/gnt_screenshot.pngbin0 -> 106656 bytes
-rw-r--r--packages/website/public/images/instant/gods_screenshot.pngbin0 -> 585005 bytes
-rw-r--r--packages/website/public/images/instant/kitty_screenshot.pngbin0 -> 208899 bytes
-rw-r--r--packages/website/public/images/instant/nmr_screenshot.pngbin0 -> 104794 bytes
-rw-r--r--packages/website/public/images/instant/rep_screenshot.pngbin0 -> 106740 bytes
-rw-r--r--packages/website/ts/components/ui/image.tsx2
-rw-r--r--packages/website/ts/components/ui/text.tsx2
-rw-r--r--packages/website/ts/containers/instant.ts30
-rw-r--r--packages/website/ts/index.tsx2
-rw-r--r--packages/website/ts/pages/instant/configurator.tsx12
-rw-r--r--packages/website/ts/pages/instant/features.tsx146
-rw-r--r--packages/website/ts/pages/instant/instant.tsx87
-rw-r--r--packages/website/ts/pages/instant/introducing_0x_instant.tsx57
-rw-r--r--packages/website/ts/pages/instant/need_more.tsx62
-rw-r--r--packages/website/ts/pages/instant/screenshots.tsx35
-rw-r--r--packages/website/ts/style/colors.ts3
-rw-r--r--packages/website/ts/types.ts1
-rw-r--r--packages/website/tslint.json3
359 files changed, 6913 insertions, 27578 deletions
diff --git a/packages/0x.js/.npmignore b/packages/0x.js/.npmignore
index d7ee80c97..312a23faa 100644
--- a/packages/0x.js/.npmignore
+++ b/packages/0x.js/.npmignore
@@ -4,7 +4,7 @@ webpack.config.js
yarn-error.log
test/
/src/
-/contract_templates/
+/abi-gen-templates/
/generated_docs/
/scripts/
/lib/src/monorepo_scripts/
diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json
index 9ff4183e7..4ee1e92be 100644
--- a/packages/0x.js/CHANGELOG.json
+++ b/packages/0x.js/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "2.0.6",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "2.0.5",
"changes": [
diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md
index 1f40bca7a..463ff923d 100644
--- a/packages/0x.js/CHANGELOG.md
+++ b/packages/0x.js/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.6 - _November 28, 2018_
+
+ * Dependencies updated
+
## v2.0.5 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index 3850e9038..aa038c302 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -1,6 +1,6 @@
{
"name": "0x.js",
- "version": "2.0.5",
+ "version": "2.0.6",
"engines": {
"node": ">=6.12"
},
@@ -42,10 +42,10 @@
},
"license": "Apache-2.0",
"devDependencies": {
- "@0x/abi-gen-wrappers": "^1.1.0",
- "@0x/contract-addresses": "^1.2.0",
- "@0x/dev-utils": "^1.0.18",
- "@0x/migrations": "^2.1.0",
+ "@0x/abi-gen-wrappers": "^2.0.0",
+ "@0x/contract-addresses": "^2.0.0",
+ "@0x/dev-utils": "^1.0.19",
+ "@0x/migrations": "^2.2.0",
"@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
@@ -73,15 +73,15 @@
},
"dependencies": {
"@0x/assert": "^1.0.18",
- "@0x/base-contract": "^3.0.7",
- "@0x/contract-wrappers": "^4.1.0",
- "@0x/order-utils": "^3.0.3",
- "@0x/order-watcher": "^2.2.5",
- "@0x/subproviders": "^2.1.5",
+ "@0x/base-contract": "^3.0.8",
+ "@0x/contract-wrappers": "^4.1.1",
+ "@0x/order-utils": "^3.0.4",
+ "@0x/order-watcher": "^2.2.6",
+ "@0x/subproviders": "^2.1.6",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@types/web3-provider-engine": "^14.0.0",
"ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
diff --git a/packages/abi-gen-templates/CHANGELOG.json b/packages/abi-gen-templates/CHANGELOG.json
index adf615b3b..baf852ad5 100644
--- a/packages/abi-gen-templates/CHANGELOG.json
+++ b/packages/abi-gen-templates/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "1.0.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"version": "1.0.0",
"changes": [
{
diff --git a/packages/abi-gen-templates/CHANGELOG.md b/packages/abi-gen-templates/CHANGELOG.md
new file mode 100644
index 000000000..1c3f21c6c
--- /dev/null
+++ b/packages/abi-gen-templates/CHANGELOG.md
@@ -0,0 +1,14 @@
+<!--
+changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
+Edit the package's CHANGELOG.json file only.
+-->
+
+CHANGELOG
+
+## v1.0.1 - _November 28, 2018_
+
+ * Dependencies updated
+
+## v1.0.0 - _Invalid date_
+
+ * Initial publish (#1305)
diff --git a/packages/abi-gen-templates/package.json b/packages/abi-gen-templates/package.json
index e06be6127..09872ab49 100644
--- a/packages/abi-gen-templates/package.json
+++ b/packages/abi-gen-templates/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/abi-gen-templates",
- "version": "1.0.0",
+ "version": "1.0.1",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/abi-gen-wrappers/CHANGELOG.json b/packages/abi-gen-wrappers/CHANGELOG.json
index f74d98afa..6905a7537 100644
--- a/packages/abi-gen-wrappers/CHANGELOG.json
+++ b/packages/abi-gen-wrappers/CHANGELOG.json
@@ -6,7 +6,8 @@
"pr": 1309,
"note": "Update Exchange artifact to receive ZRX asset data as a constructor argument"
}
- ]
+ ],
+ "timestamp": 1543401373
},
{
"version": "1.1.0",
diff --git a/packages/abi-gen-wrappers/CHANGELOG.md b/packages/abi-gen-wrappers/CHANGELOG.md
index 7d359f07b..30a10d6bd 100644
--- a/packages/abi-gen-wrappers/CHANGELOG.md
+++ b/packages/abi-gen-wrappers/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.0 - _November 28, 2018_
+
+ * Update Exchange artifact to receive ZRX asset data as a constructor argument (#1309)
+
## v1.1.0 - _November 21, 2018_
* `deployFrom0xArtifactAsync` additionally accepts artifacts that conform to the `SimpleContractArtifact` interface (#1298)
diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json
index 1b7015d55..e4f103cf7 100644
--- a/packages/abi-gen-wrappers/package.json
+++ b/packages/abi-gen-wrappers/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/abi-gen-wrappers",
- "version": "1.1.0",
+ "version": "2.0.0",
"engines": {
"node": ">=6.12"
},
@@ -31,18 +31,18 @@
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.17",
- "@0x/abi-gen-templates": "^1.0.0",
+ "@0x/abi-gen-templates": "^1.0.1",
"@0x/tslint-config": "^1.0.10",
"@0x/types": "^1.3.0",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5",
"shx": "^0.2.2"
},
"dependencies": {
- "@0x/base-contract": "^3.0.7"
+ "@0x/base-contract": "^3.0.8"
},
"publishConfig": {
"access": "public"
diff --git a/packages/abi-gen/README.md b/packages/abi-gen/README.md
index 20b9d4f30..214d8f257 100644
--- a/packages/abi-gen/README.md
+++ b/packages/abi-gen/README.md
@@ -4,7 +4,7 @@ This package allows you to generate TypeScript contract wrappers from ABI files.
It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach.
You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.
-[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate the contract wrappers used by 0x.js.e
+[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/abi-gen-templates) are the templates used to generate the contract wrappers used by 0x.js.e
## Installation
@@ -44,7 +44,7 @@ You need to also specify the location of your main template used for every contr
## How to write custom templates?
-The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates) and start adjusting them for your needs.
+The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen-templates) and start adjusting them for your needs.
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available.
diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json
index b7a83ccfc..4ff83018e 100644
--- a/packages/asset-buyer/CHANGELOG.json
+++ b/packages/asset-buyer/CHANGELOG.json
@@ -1,5 +1,22 @@
[
{
+ "version": "3.0.3",
+ "changes": [
+ {
+ "note": "Update SRA order provider to include Dai"
+ }
+ ]
+ },
+ {
+ "timestamp": 1543401373,
+ "version": "3.0.2",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"version": "3.0.1",
"changes": [
{
diff --git a/packages/asset-buyer/CHANGELOG.md b/packages/asset-buyer/CHANGELOG.md
index 20702a531..be3ef67d1 100644
--- a/packages/asset-buyer/CHANGELOG.md
+++ b/packages/asset-buyer/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.2 - _November 28, 2018_
+
+ * Dependencies updated
+
## v3.0.1 - _November 21, 2018_
* Dependencies updated (#1276)
diff --git a/packages/asset-buyer/package.json b/packages/asset-buyer/package.json
index 50b276704..780b2e3e2 100644
--- a/packages/asset-buyer/package.json
+++ b/packages/asset-buyer/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/asset-buyer",
- "version": "3.0.1",
+ "version": "3.0.2",
"engines": {
"node": ">=6.12"
},
@@ -37,15 +37,15 @@
"homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md",
"dependencies": {
"@0x/assert": "^1.0.18",
- "@0x/connect": "^3.0.7",
- "@0x/contract-wrappers": "^4.1.0",
+ "@0x/connect": "^3.0.8",
+ "@0x/contract-wrappers": "^4.1.1",
"@0x/json-schemas": "^2.1.2",
- "@0x/order-utils": "^3.0.3",
- "@0x/subproviders": "^2.1.5",
+ "@0x/order-utils": "^3.0.4",
+ "@0x/subproviders": "^2.1.6",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"ethereum-types": "^1.1.2",
"lodash": "^4.17.5"
},
diff --git a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts
index be1fc55d6..813c9923b 100644
--- a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts
+++ b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts
@@ -100,6 +100,12 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider {
} catch (err) {
throw new Error(AssetBuyerError.StandardRelayerApiError);
}
- return _.map(response.records, item => item.assetDataB.assetData);
+ return _.map(response.records, item => {
+ if (item.assetDataA.assetData === takerAssetData) {
+ return item.assetDataB.assetData;
+ } else {
+ return item.assetDataA.assetData;
+ }
+ });
}
}
diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json
index 66633136c..e4dff5530 100644
--- a/packages/base-contract/CHANGELOG.json
+++ b/packages/base-contract/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "3.0.8",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "3.0.7",
"changes": [
diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md
index 35032fc9f..f61b6c6ce 100644
--- a/packages/base-contract/CHANGELOG.md
+++ b/packages/base-contract/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.8 - _November 28, 2018_
+
+ * Dependencies updated
+
## v3.0.7 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json
index 2ae42d66b..2a331b3cb 100644
--- a/packages/base-contract/package.json
+++ b/packages/base-contract/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/base-contract",
- "version": "3.0.7",
+ "version": "3.0.8",
"engines": {
"node": ">=6.12"
},
@@ -42,7 +42,7 @@
"dependencies": {
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json
index db9d8c92a..3abb895a7 100644
--- a/packages/connect/CHANGELOG.json
+++ b/packages/connect/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "3.0.8",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "3.0.7",
"changes": [
diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md
index 5e4013322..1dfc2672d 100644
--- a/packages/connect/CHANGELOG.md
+++ b/packages/connect/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.8 - _November 28, 2018_
+
+ * Dependencies updated
+
## v3.0.7 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/connect/package.json b/packages/connect/package.json
index d05f24463..2f3d30d84 100644
--- a/packages/connect/package.json
+++ b/packages/connect/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/connect",
- "version": "3.0.7",
+ "version": "3.0.8",
"engines": {
"node": ">=6.12"
},
@@ -46,7 +46,7 @@
"dependencies": {
"@0x/assert": "^1.0.18",
"@0x/json-schemas": "^2.1.2",
- "@0x/order-utils": "^3.0.3",
+ "@0x/order-utils": "^3.0.4",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json
index e65351c7e..21ffaf510 100644
--- a/packages/contract-addresses/CHANGELOG.json
+++ b/packages/contract-addresses/CHANGELOG.json
@@ -1,5 +1,19 @@
[
{
+ "version": "2.0.0",
+ "changes": [
+ {
+ "note": "Redeployed Rinkeby with testnet Exchange artifact",
+ "pr": 1318
+ },
+ {
+ "note": "Added Ganache snapshot addresses for network 50",
+ "pr": 1318
+ }
+ ],
+ "timestamp": 1543401373
+ },
+ {
"version": "1.2.0",
"changes": [
{
diff --git a/packages/contract-addresses/CHANGELOG.md b/packages/contract-addresses/CHANGELOG.md
index 9801831f7..c006c3b22 100644
--- a/packages/contract-addresses/CHANGELOG.md
+++ b/packages/contract-addresses/CHANGELOG.md
@@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.0.0 - _November 28, 2018_
+
+ * Redeployed Rinkeby with testnet Exchange artifact (#1318)
+ * Added Ganache snapshot addresses for network 50 (#1318)
+
## v1.2.0 - _November 21, 2018_
* Rinkeby Deployment
diff --git a/packages/contract-addresses/package.json b/packages/contract-addresses/package.json
index 9f0db4d30..c75ae6efa 100644
--- a/packages/contract-addresses/package.json
+++ b/packages/contract-addresses/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/contract-addresses",
- "version": "1.2.0",
+ "version": "2.0.0",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts
index 57358dd38..7989631e3 100644
--- a/packages/contract-addresses/src/index.ts
+++ b/packages/contract-addresses/src/index.ts
@@ -16,6 +16,7 @@ export enum NetworkId {
Ropsten = 3,
Rinkeby = 4,
Kovan = 42,
+ Ganache = 50,
}
const networkToAddresses: { [networkId: number]: ContractAddresses } = {
@@ -40,14 +41,14 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
orderValidator: '0x90431a90516ab49af23a0530e04e8c7836e7122f',
},
4: {
- erc20Proxy: '0x3e809c563c15a295e832e37053798ddc8d6c8dab',
- erc721Proxy: '0x8e1ff02637cb5e39f2fa36c14706aa348b065b09',
- zrxToken: '0x2727e688b8fd40b198cd5fe6e408e00494a06f07',
+ exchange: '0xbce0b5f6eb618c565c3e5f5cd69652bbc279f44e',
+ erc20Proxy: '0x2f5ae4f6106e89b4147651688a92256885c5f410',
+ erc721Proxy: '0x7656d773e11ff7383a14dcf09a9c50990481cd10',
+ zrxToken: '0x8080c7e4b81ecf23aa6f877cfbfd9b0c228c6ffa',
etherToken: '0xc778417e063141139fce010982780140aa0cd5ab',
- exchange: '0x22ebc052f43a88efa06379426120718170f2204e',
- assetProxyOwner: '0x1da52d1d3a3acfa0a1836b737393b4e9931268fc',
- forwarder: '0xd2dbf3250a764eaaa94fa0c84ed87c0edc8ed04e',
- orderValidator: '0x39c3fc9f4d8430af2713306ce80c584752d9e1c7',
+ assetProxyOwner: '0xe1703da878afcebff5b7624a826902af475b9c03',
+ forwarder: '0x2d40589abbdee84961f3a7656b9af7adb0ee5ab4',
+ orderValidator: '0x0c5173a51e26b29d6126c686756fb9fbef71f762',
},
42: {
erc20Proxy: '0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e',
@@ -59,6 +60,17 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = {
forwarder: '0x17992e4ffb22730138e4b62aaa6367fa9d3699a6',
orderValidator: '0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d',
},
+ // NetworkId 50 represents our Ganache snapshot generated from migrations.
+ 50: {
+ exchange: '0x48bacb9266a570d521063ef5dd96e61686dbe788',
+ erc20Proxy: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
+ erc721Proxy: '0x1d7022f5b17d2f8b695918fb48fa1089c9f85401',
+ zrxToken: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c',
+ etherToken: '0x0b1ba0af832d7c05fd64161e0db78e85978e8082',
+ assetProxyOwner: '0x34d402f14d58e001d8efbe6585051bf9706aa064',
+ forwarder: '0xb69e673309512a9d726f87304c6984054f87a93b',
+ orderValidator: '0xe86bb98fcf9bff3512c74589b78fb168200cc546',
+ },
};
/**
diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json
index b75ad5766..03c88e71a 100644
--- a/packages/contract-artifacts/CHANGELOG.json
+++ b/packages/contract-artifacts/CHANGELOG.json
@@ -6,7 +6,8 @@
"pr": 1309,
"note": "Update Exchange artifact to receive ZRX asset data as a constructor argument"
}
- ]
+ ],
+ "timestamp": 1543401373
},
{
"version": "1.1.0",
diff --git a/packages/contract-artifacts/CHANGELOG.md b/packages/contract-artifacts/CHANGELOG.md
index b3c399985..9e48058f5 100644
--- a/packages/contract-artifacts/CHANGELOG.md
+++ b/packages/contract-artifacts/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.1.2 - _November 28, 2018_
+
+ * Update Exchange artifact to receive ZRX asset data as a constructor argument (#1309)
+
## v1.1.0 - _November 9, 2018_
* Update Forwarder artifact (#1192)
diff --git a/packages/contract-artifacts/package.json b/packages/contract-artifacts/package.json
index 9c25e3ac5..71d887545 100644
--- a/packages/contract-artifacts/package.json
+++ b/packages/contract-artifacts/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/contract-artifacts",
- "version": "1.1.0",
+ "version": "1.1.2",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/contract-wrappers/.npmignore b/packages/contract-wrappers/.npmignore
index 6a3eb57bd..6a222fd45 100644
--- a/packages/contract-wrappers/.npmignore
+++ b/packages/contract-wrappers/.npmignore
@@ -5,7 +5,7 @@ yarn-error.log
test/
/src/
/_bundles/
-/contract_templates/
+/abi-gen-templates/
/generated_docs/
/scripts/
/lib/src/monorepo_scripts/
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json
index 711ab49a1..006a0904d 100644
--- a/packages/contract-wrappers/CHANGELOG.json
+++ b/packages/contract-wrappers/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "4.1.1",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"version": "4.1.0",
"changes": [
{
diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md
index 201c65a4c..ebdcc9638 100644
--- a/packages/contract-wrappers/CHANGELOG.md
+++ b/packages/contract-wrappers/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v4.1.1 - _November 28, 2018_
+
+ * Dependencies updated
+
## v4.1.0 - _November 21, 2018_
* Add a `nonce` field for `TxOpts` so that it's now possible to re-broadcast stuck transactions with a higher gas amount (#1292)
diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json
index 999375ea5..e11d1a63e 100644
--- a/packages/contract-wrappers/package.json
+++ b/packages/contract-wrappers/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/contract-wrappers",
- "version": "4.1.0",
+ "version": "4.1.1",
"description": "Smart TS wrappers for 0x smart contracts",
"keywords": [
"0xproject",
@@ -37,9 +37,9 @@
"node": ">=6.0.0"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
- "@0x/migrations": "^2.1.0",
- "@0x/subproviders": "^2.1.5",
+ "@0x/dev-utils": "^1.0.19",
+ "@0x/migrations": "^2.2.0",
+ "@0x/subproviders": "^2.1.6",
"@0x/tslint-config": "^1.0.10",
"@types/lodash": "4.14.104",
"@types/mocha": "^2.2.42",
@@ -65,17 +65,17 @@
"web3-provider-engine": "14.0.6"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.1.0",
+ "@0x/abi-gen-wrappers": "^2.0.0",
"@0x/assert": "^1.0.18",
- "@0x/contract-addresses": "^1.2.0",
- "@0x/contract-artifacts": "^1.1.0",
- "@0x/fill-scenarios": "^1.0.13",
+ "@0x/contract-addresses": "^2.0.0",
+ "@0x/contract-artifacts": "^1.1.2",
+ "@0x/fill-scenarios": "^1.0.14",
"@0x/json-schemas": "^2.1.2",
- "@0x/order-utils": "^3.0.3",
+ "@0x/order-utils": "^3.0.4",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"ethereum-types": "^1.1.2",
"ethereumjs-blockstream": "6.0.0",
"ethereumjs-util": "^5.1.1",
diff --git a/packages/contracts/.solhint.json b/packages/contracts/.solhint.json
deleted file mode 100644
index 076afe9f3..000000000
--- a/packages/contracts/.solhint.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "extends": "default",
- "rules": {
- "avoid-low-level-calls": false,
- "avoid-tx-origin": "warn",
- "bracket-align": false,
- "code-complexity": false,
- "const-name-snakecase": "error",
- "expression-indent": "error",
- "function-max-lines": false,
- "func-order": "error",
- "indent": ["error", 4],
- "max-line-length": ["warn", 160],
- "no-inline-assembly": false,
- "quotes": ["error", "double"],
- "separate-by-one-line-in-contract": "error",
- "space-after-comma": "error",
- "statement-indent": "error"
- }
-}
diff --git a/packages/contracts/.solhintignore b/packages/contracts/.solhintignore
deleted file mode 100644
index 1e33ec53b..000000000
--- a/packages/contracts/.solhintignore
+++ /dev/null
@@ -1,3 +0,0 @@
-contracts/tokens/ZRXToken/ERC20Token_v1.sol
-contracts/tokens/ZRXToken/Token_v1.sol
-contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol
diff --git a/packages/contracts/CHANGELOG.json b/packages/contracts/CHANGELOG.json
deleted file mode 100644
index 00f94c83b..000000000
--- a/packages/contracts/CHANGELOG.json
+++ /dev/null
@@ -1,125 +0,0 @@
-[
- {
- "name": "OrderValidator",
- "version": "1.0.1",
- "changes": [
- {
- "note": "remove `getApproved` check from ERC721 approval query",
- "pr": 1149
- }
- ]
- },
- {
- "name": "Forwarder",
- "version": "1.1.0",
- "changes": [
- {
- "note": "Round up when calculating remaining amounts in marketBuy functions",
- "pr": 1162,
- "networks": {
- "1": "0x5468a1dc173652ee28d249c271fa9933144746b1",
- "3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
- "42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6"
- }
- }
- ]
- },
- {
- "name": "Forwarder",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6",
- "3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3",
- "42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8"
- }
- }
- ]
- },
- {
- "name": "OrderValidator",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x9463e518dea6810309563c81d5266c1b1d149138",
- "3": "0x90431a90516ab49af23a0530e04e8c7836e7122f",
- "42": "0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d"
- }
- }
- ]
- },
- {
- "name": "Exchange",
- "version": "2.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b",
- "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf",
- "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2"
- }
- }
- ]
- },
- {
- "name": "ERC20Proxy",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
- "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
- "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
- }
- }
- ]
- },
- {
- "name": "ERC721Proxy",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
- "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
- "42": "0x2a9127c745688a165106c11cd4d647d2220af821"
- }
- }
- ]
- },
- {
- "name": "AssetProxyOwner",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v2 deploy",
- "networks": {
- "1": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6",
- "3": "0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b",
- "42": "0x2c824d2882baa668e0d5202b1e7f2922278703f8"
- }
- }
- ]
- },
- {
- "name": "ZRXToken",
- "version": "1.0.0",
- "changes": [
- {
- "note": "protocol v1 deploy",
- "networks": {
- "1": "0xe41d2489571d322189246dafa5ebde1f4699f498",
- "3": "0xff67881f8d12f372d91baae9752eb3631ff0ed00",
- "42": "0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa"
- }
- }
- ]
- }
-]
diff --git a/packages/contracts/README.md b/packages/contracts/README.md
deleted file mode 100644
index 97a2816ff..000000000
--- a/packages/contracts/README.md
+++ /dev/null
@@ -1,129 +0,0 @@
-## Contracts
-
-Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [CHANGELOG](./CHANGELOG.json) of this package.
-
-## Usage
-
-Contracts that make up and interact with version 2.0.0 of the protocol can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
-
-* [protocol](./contracts/protocol)
- * This directory contains the contracts that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
-* [extensions](./contracts/extensions)
- * This directory contains contracts that interact with the 2.0.0 contracts and will be used in production, such as the [Forwarder](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract.
-* [examples](./contracts/examples)
- * This directory contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others.
-* [tokens](./contracts/tokens)
- * This directory contains implementations of different tokens and token standards, including [wETH](https://weth.io/), ZRX, [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md), and [ERC721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md).
-* [multisig](./contracts/multisig)
- * This directory contains the [Gnosis MultiSigWallet](https://github.com/gnosis/MultiSigWallet) and a custom extension that adds a timelock to transactions within the MultiSigWallet.
-* [utils](./contracts/utils)
- * This directory contains libraries and utils that are shared across all of the other directories.
-* [test](./contracts/test)
- * This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
-
-## Bug bounty
-
-A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
-
-## Contributing
-
-We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
-
-For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
-
-Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
-
-### Install Dependencies
-
-If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
-
-```bash
-yarn config set workspaces-experimental true
-```
-
-Then install dependencies
-
-```bash
-yarn install
-```
-
-### Build
-
-To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
-
-```bash
-PKG=contracts yarn build
-```
-
-Or continuously rebuild on change:
-
-```bash
-PKG=contracts yarn watch
-```
-
-### Clean
-
-```bash
-yarn clean
-```
-
-### Lint
-
-```bash
-yarn lint
-```
-
-### Run Tests
-
-```bash
-yarn test
-```
-
-#### Testing options
-
-###### Revert stack traces
-
-If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with:
-
-```
-yarn test:trace
-```
-
-**Note:** This currently slows down the test runs and is therefore not enabled by default.
-
-###### Backing Ethereum node
-
-By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run:
-
-```bash
-TEST_PROVIDER=geth yarn test
-```
-
-###### Code coverage
-
-In order to see the Solidity code coverage output generated by `@0x/sol-cov`, run:
-
-```
-yarn test:coverage
-```
-
-###### Gas profiler
-
-In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode.
-
-**Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling.
-
-```
-TEST_PROVIDER=geth yarn test:profiler
-```
-
-You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile.
-
-```typescript
-import { profiler } from './utils/profiler';
-profiler.start();
-// Some call to a smart contract
-profiler.stop();
-```
-
-Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable.
diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json
deleted file mode 100644
index af3980b4e..000000000
--- a/packages/contracts/compiler.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "artifactsDir": "./generated-artifacts",
- "contractsDir": "./contracts",
- "compilerSettings": {
- "optimizer": {
- "enabled": true,
- "runs": 1000000
- },
- "outputSelection": {
- "*": {
- "*": [
- "abi",
- "evm.bytecode.object",
- "evm.bytecode.sourceMap",
- "evm.deployedBytecode.object",
- "evm.deployedBytecode.sourceMap"
- ]
- }
- }
- },
- "contracts": [
- "AssetProxyOwner",
- "DummyERC20Token",
- "DummyERC721Receiver",
- "DummyERC721Token",
- "DummyMultipleReturnERC20Token",
- "DummyNoReturnERC20Token",
- "ERC20Proxy",
- "ERC20Token",
- "ERC721Token",
- "ERC721Proxy",
- "Exchange",
- "ExchangeWrapper",
- "Forwarder",
- "IAssetData",
- "IAssetProxy",
- "InvalidERC721Receiver",
- "IValidator",
- "IWallet",
- "MixinAuthorizable",
- "MultiSigWallet",
- "MultiSigWalletWithTimeLock",
- "OrderValidator",
- "ReentrantERC20Token",
- "TestAssetProxyOwner",
- "TestAssetProxyDispatcher",
- "TestConstants",
- "TestLibBytes",
- "TestLibs",
- "TestExchangeInternals",
- "TestSignatureValidator",
- "TestStaticCallReceiver",
- "Validator",
- "Wallet",
- "WETH9",
- "Whitelist",
- "ZRXToken"
- ]
-}
diff --git a/packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol b/packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol
deleted file mode 100644
index 2fa0e3c5e..000000000
--- a/packages/contracts/contracts/examples/ExchangeWrapper/ExchangeWrapper.sol
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-
-
-contract ExchangeWrapper {
-
- // Exchange contract.
- // solhint-disable-next-line var-name-mixedcase
- IExchange internal EXCHANGE;
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- }
-
- /// @dev Cancels all orders created by sender with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to this contract.
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash.
- /// @param makerSignature Proof that maker wishes to call this function with given params.
- function cancelOrdersUpTo(
- uint256 targetOrderEpoch,
- uint256 salt,
- bytes makerSignature
- )
- external
- {
- address makerAddress = msg.sender;
-
- // Encode arguments into byte array.
- bytes memory data = abi.encodeWithSelector(
- EXCHANGE.cancelOrdersUpTo.selector,
- targetOrderEpoch
- );
-
- // Call `cancelOrdersUpTo` via `executeTransaction`.
- EXCHANGE.executeTransaction(
- salt,
- makerAddress,
- data,
- makerSignature
- );
- }
-
- /// @dev Fills an order using `msg.sender` as the taker.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash.
- /// @param orderSignature Proof that order has been created by maker.
- /// @param takerSignature Proof that taker wishes to call this function with given params.
- function fillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- uint256 salt,
- bytes memory orderSignature,
- bytes memory takerSignature
- )
- public
- {
- address takerAddress = msg.sender;
-
- // Encode arguments into byte array.
- bytes memory data = abi.encodeWithSelector(
- EXCHANGE.fillOrder.selector,
- order,
- takerAssetFillAmount,
- orderSignature
- );
-
- // Call `fillOrder` via `executeTransaction`.
- EXCHANGE.executeTransaction(
- salt,
- takerAddress,
- data,
- takerSignature
- );
- }
-}
diff --git a/packages/contracts/contracts/examples/Validator/Validator.sol b/packages/contracts/contracts/examples/Validator/Validator.sol
deleted file mode 100644
index 72ed528ba..000000000
--- a/packages/contracts/contracts/examples/Validator/Validator.sol
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-
- 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 "../../protocol/Exchange/interfaces/IValidator.sol";
-
-
-contract Validator is
- IValidator
-{
-
- // The single valid signer for this wallet.
- // solhint-disable-next-line var-name-mixedcase
- address internal VALID_SIGNER;
-
- /// @dev constructs a new `Validator` with a single valid signer.
- /// @param validSigner The sole, valid signer.
- constructor (address validSigner) public {
- VALID_SIGNER = validSigner;
- }
-
- /// @dev Verifies that a signature is valid. `signer` must match `VALID_SIGNER`.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of signature.
- // solhint-disable no-unused-vars
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid)
- {
- return (signerAddress == VALID_SIGNER);
- }
- // solhint-enable no-unused-vars
-}
diff --git a/packages/contracts/contracts/examples/Wallet/Wallet.sol b/packages/contracts/contracts/examples/Wallet/Wallet.sol
deleted file mode 100644
index b75021a31..000000000
--- a/packages/contracts/contracts/examples/Wallet/Wallet.sol
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
- 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 "../../protocol/Exchange/interfaces/IWallet.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-
-
-contract Wallet is
- IWallet
-{
- using LibBytes for bytes;
-
- // The owner of this wallet.
- // solhint-disable-next-line var-name-mixedcase
- address internal WALLET_OWNER;
-
- /// @dev constructs a new `Wallet` with a single owner.
- /// @param walletOwner The owner of this wallet.
- constructor (address walletOwner) public {
- WALLET_OWNER = walletOwner;
- }
-
- /// @dev Validates an EIP712 signature.
- /// The signer must match the owner of this wallet.
- /// @param hash Message hash that is signed.
- /// @param eip712Signature Proof of signing.
- /// @return Validity of signature.
- function isValidSignature(
- bytes32 hash,
- bytes eip712Signature
- )
- external
- view
- returns (bool isValid)
- {
- require(
- eip712Signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
-
- uint8 v = uint8(eip712Signature[0]);
- bytes32 r = eip712Signature.readBytes32(1);
- bytes32 s = eip712Signature.readBytes32(33);
- address recoveredAddress = ecrecover(hash, v, r, s);
- isValid = WALLET_OWNER == recoveredAddress;
- return isValid;
- }
-}
diff --git a/packages/contracts/contracts/examples/Whitelist/Whitelist.sol b/packages/contracts/contracts/examples/Whitelist/Whitelist.sol
deleted file mode 100644
index e4e25038c..000000000
--- a/packages/contracts/contracts/examples/Whitelist/Whitelist.sol
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../utils/Ownable/Ownable.sol";
-
-
-contract Whitelist is
- Ownable
-{
-
- // Mapping of address => whitelist status.
- mapping (address => bool) public isWhitelisted;
-
- // Exchange contract.
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
- bytes internal TX_ORIGIN_SIGNATURE;
- // solhint-enable var-name-mixedcase
-
- byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x05";
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- TX_ORIGIN_SIGNATURE = abi.encodePacked(address(this), VALIDATOR_SIGNATURE_BYTE);
- }
-
- /// @dev Adds or removes an address from the whitelist.
- /// @param target Address to add or remove from whitelist.
- /// @param isApproved Whitelist status to assign to address.
- function updateWhitelistStatus(
- address target,
- bool isApproved
- )
- external
- onlyOwner
- {
- isWhitelisted[target] = isApproved;
- }
-
- /// @dev Verifies signer is same as signer of current Ethereum transaction.
- /// NOTE: This function can currently be used to validate signatures coming from outside of this contract.
- /// Extra safety checks can be added for a production contract.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- // solhint-disable no-unused-vars
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid)
- {
- // solhint-disable-next-line avoid-tx-origin
- return signerAddress == tx.origin;
- }
- // solhint-enable no-unused-vars
-
- /// @dev Fills an order using `msg.sender` as the taker.
- /// The transaction will revert if both the maker and taker are not whitelisted.
- /// Orders should specify this contract as the `senderAddress` in order to gaurantee
- /// that both maker and taker have been whitelisted.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param salt Arbitrary value to gaurantee uniqueness of 0x transaction hash.
- /// @param orderSignature Proof that order has been created by maker.
- function fillOrderIfWhitelisted(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- uint256 salt,
- bytes memory orderSignature
- )
- public
- {
- address takerAddress = msg.sender;
-
- // This contract must be the entry point for the transaction.
- require(
- // solhint-disable-next-line avoid-tx-origin
- takerAddress == tx.origin,
- "INVALID_SENDER"
- );
-
- // Check if maker is on the whitelist.
- require(
- isWhitelisted[order.makerAddress],
- "MAKER_NOT_WHITELISTED"
- );
-
- // Check if taker is on the whitelist.
- require(
- isWhitelisted[takerAddress],
- "TAKER_NOT_WHITELISTED"
- );
-
- // Encode arguments into byte array.
- bytes memory data = abi.encodeWithSelector(
- EXCHANGE.fillOrder.selector,
- order,
- takerAssetFillAmount,
- orderSignature
- );
-
- // Call `fillOrder` via `executeTransaction`.
- EXCHANGE.executeTransaction(
- salt,
- takerAddress,
- data,
- TX_ORIGIN_SIGNATURE
- );
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/Forwarder.sol b/packages/contracts/contracts/extensions/Forwarder/Forwarder.sol
deleted file mode 100644
index 94dec40ed..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/Forwarder.sol
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./MixinWeth.sol";
-import "./MixinForwarderCore.sol";
-import "./libs/LibConstants.sol";
-import "./MixinAssets.sol";
-import "./MixinExchangeWrapper.sol";
-
-
-// solhint-disable no-empty-blocks
-contract Forwarder is
- LibConstants,
- MixinWeth,
- MixinAssets,
- MixinExchangeWrapper,
- MixinForwarderCore
-{
- constructor (
- address _exchange,
- bytes memory _zrxAssetData,
- bytes memory _wethAssetData
- )
- public
- LibConstants(
- _exchange,
- _zrxAssetData,
- _wethAssetData
- )
- MixinForwarderCore()
- {}
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol b/packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol
deleted file mode 100644
index 43efb5ff3..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/MixinAssets.sol
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-
- 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/LibBytes/LibBytes.sol";
-import "../../utils/Ownable/Ownable.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
-import "../../tokens/ERC721Token/IERC721Token.sol";
-import "./libs/LibConstants.sol";
-import "./mixins/MAssets.sol";
-
-
-contract MixinAssets is
- Ownable,
- LibConstants,
- MAssets
-{
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
-
- /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
- /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
- /// used to withdraw assets that were accidentally sent to this contract.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of ERC20 token to withdraw.
- function withdrawAsset(
- bytes assetData,
- uint256 amount
- )
- external
- onlyOwner
- {
- transferAssetToSender(assetData, amount);
- }
-
- /// @dev Transfers given amount of asset to sender.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of asset to transfer to sender.
- function transferAssetToSender(
- bytes memory assetData,
- uint256 amount
- )
- internal
- {
- bytes4 proxyId = assetData.readBytes4(0);
-
- if (proxyId == ERC20_DATA_ID) {
- transferERC20Token(assetData, amount);
- } else if (proxyId == ERC721_DATA_ID) {
- transferERC721Token(assetData, amount);
- } else {
- revert("UNSUPPORTED_ASSET_PROXY");
- }
- }
-
- /// @dev Decodes ERC20 assetData and transfers given amount to sender.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of asset to transfer to sender.
- function transferERC20Token(
- bytes memory assetData,
- uint256 amount
- )
- internal
- {
- address token = assetData.readAddress(16);
-
- // Transfer tokens.
- // We do a raw call so we can check the success separate
- // from the return data.
- bool success = token.call(abi.encodeWithSelector(
- ERC20_TRANSFER_SELECTOR,
- msg.sender,
- amount
- ));
- require(
- success,
- "TRANSFER_FAILED"
- );
-
- // Check return data.
- // If there is no return data, we assume the token incorrectly
- // does not return a bool. In this case we expect it to revert
- // on failure, which was handled above.
- // If the token does return data, we require that it is a single
- // value that evaluates to true.
- assembly {
- if returndatasize {
- success := 0
- if eq(returndatasize, 32) {
- // First 64 bytes of memory are reserved scratch space
- returndatacopy(0, 0, 32)
- success := mload(0)
- }
- }
- }
- require(
- success,
- "TRANSFER_FAILED"
- );
- }
-
- /// @dev Decodes ERC721 assetData and transfers given amount to sender.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of asset to transfer to sender.
- function transferERC721Token(
- bytes memory assetData,
- uint256 amount
- )
- internal
- {
- require(
- amount == 1,
- "INVALID_AMOUNT"
- );
- // Decode asset data.
- address token = assetData.readAddress(16);
- uint256 tokenId = assetData.readUint256(36);
-
- // Perform transfer.
- IERC721Token(token).transferFrom(
- address(this),
- msg.sender,
- tokenId
- );
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol b/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol
deleted file mode 100644
index 4991c0ea5..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./libs/LibConstants.sol";
-import "./mixins/MExchangeWrapper.sol";
-import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
-import "../../protocol/Exchange/libs/LibMath.sol";
-
-
-contract MixinExchangeWrapper is
- LibAbiEncoder,
- LibFillResults,
- LibMath,
- LibConstants,
- MExchangeWrapper
-{
- /// @dev Fills the input order.
- /// Returns false if the transaction would otherwise revert.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- // ABI encode calldata for `fillOrder`
- bytes memory fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
-
- address exchange = address(EXCHANGE);
-
- // Call `fillOrder` and handle any exceptions gracefully
- assembly {
- let success := call(
- gas, // forward all gas
- exchange, // call address of Exchange contract
- 0, // transfer 0 wei
- add(fillOrderCalldata, 32), // pointer to start of input (skip array length in first 32 bytes)
- mload(fillOrderCalldata), // length of input
- fillOrderCalldata, // write output over input
- 128 // output size is 128 bytes
- )
- if success {
- mstore(fillResults, mload(fillOrderCalldata))
- mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32)))
- mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64)))
- mstore(add(fillResults, 96), mload(add(fillOrderCalldata, 96)))
- }
- }
- // fillResults values will be 0 by default if call was unsuccessful
- return fillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param wethSellAmount Desired amount of WETH to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellWeth(
- LibOrder.Order[] memory orders,
- uint256 wethSellAmount,
- bytes[] memory signatures
- )
- internal
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
- bytes memory wethAssetData = WETH_ASSET_DATA;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // We assume that asset being sold by taker is WETH for each order.
- orders[i].makerAssetData = makerAssetData;
- orders[i].takerAssetData = wethAssetData;
-
- // Calculate the remaining amount of WETH to sell
- uint256 remainingTakerAssetFillAmount = safeSub(wethSellAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of WETH
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= wethSellAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyExactAmountWithWeth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- internal
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
- bytes memory wethAssetData = WETH_ASSET_DATA;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // We assume that asset being sold by taker is WETH for each order.
- orders[i].makerAssetData = makerAssetData;
- orders[i].takerAssetData = wethAssetData;
-
- // Calculate the remaining amount of makerAsset to buy
- uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
-
- // Convert the remaining amount of makerAsset to buy into remaining amount
- // of takerAsset to sell, assuming entire amount can be sold in the current order.
- // We round up because the exchange rate computed by fillOrder rounds in favor
- // of the Maker. In this case we want to overestimate the amount of takerAsset.
- uint256 remainingTakerAssetFillAmount = getPartialAmountCeil(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of makerAsset has been bought
- uint256 makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount;
- if (makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
-
- require(
- makerAssetFilledAmount >= makerAssetFillAmount,
- "COMPLETE_FILL_FAILED"
- );
- return totalFillResults;
- }
-
- /// @dev Buys zrxBuyAmount of ZRX fee tokens, taking into account ZRX fees for each order. This will guarantee
- /// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
- /// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
- /// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
- /// @param zrxBuyAmount Desired amount of ZRX to buy.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return totalFillResults Amounts filled and fees paid by maker and taker.
- function marketBuyExactZrxWithWeth(
- LibOrder.Order[] memory orders,
- uint256 zrxBuyAmount,
- bytes[] memory signatures
- )
- internal
- returns (FillResults memory totalFillResults)
- {
- // Do nothing if zrxBuyAmount == 0
- if (zrxBuyAmount == 0) {
- return totalFillResults;
- }
-
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- bytes memory wethAssetData = WETH_ASSET_DATA;
- uint256 zrxPurchased = 0;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // All of these are ZRX/WETH, so we can drop the respective assetData from calldata.
- orders[i].makerAssetData = zrxAssetData;
- orders[i].takerAssetData = wethAssetData;
-
- // Calculate the remaining amount of ZRX to buy.
- uint256 remainingZrxBuyAmount = safeSub(zrxBuyAmount, zrxPurchased);
-
- // Convert the remaining amount of ZRX to buy into remaining amount
- // of WETH to sell, assuming entire amount can be sold in the current order.
- // We round up because the exchange rate computed by fillOrder rounds in favor
- // of the Maker. In this case we want to overestimate the amount of takerAsset.
- uint256 remainingWethSellAmount = getPartialAmountCeil(
- orders[i].takerAssetAmount,
- safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
- remainingZrxBuyAmount
- );
-
- // Attempt to sell the remaining amount of WETH.
- FillResults memory singleFillResult = fillOrderNoThrow(
- orders[i],
- remainingWethSellAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker.
- addFillResults(totalFillResults, singleFillResult);
- zrxPurchased = safeSub(totalFillResults.makerAssetFilledAmount, totalFillResults.takerFeePaid);
-
- // Stop execution if the entire amount of ZRX has been bought.
- if (zrxPurchased >= zrxBuyAmount) {
- break;
- }
- }
-
- require(
- zrxPurchased >= zrxBuyAmount,
- "COMPLETE_FILL_FAILED"
- );
- return totalFillResults;
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol b/packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol
deleted file mode 100644
index 54487f726..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/MixinForwarderCore.sol
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./libs/LibConstants.sol";
-import "./mixins/MWeth.sol";
-import "./mixins/MAssets.sol";
-import "./mixins/MExchangeWrapper.sol";
-import "./interfaces/IForwarderCore.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
-import "../../protocol/Exchange/libs/LibMath.sol";
-
-
-contract MixinForwarderCore is
- LibFillResults,
- LibMath,
- LibConstants,
- MWeth,
- MAssets,
- MExchangeWrapper,
- IForwarderCore
-{
- using LibBytes for bytes;
-
- /// @dev Constructor approves ERC20 proxy to transfer ZRX and WETH on this contract's behalf.
- constructor ()
- public
- {
- address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
- require(
- proxyAddress != address(0),
- "UNREGISTERED_ASSET_PROXY"
- );
- ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
- ZRX_TOKEN.approve(proxyAddress, MAX_UINT);
- }
-
- /// @dev Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketSellOrdersWithEth(
- LibOrder.Order[] memory orders,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- FillResults memory orderFillResults,
- FillResults memory feeOrderFillResults
- )
- {
- // Convert ETH to WETH.
- convertEthToWeth();
-
- uint256 wethSellAmount;
- uint256 zrxBuyAmount;
- uint256 makerAssetAmountPurchased;
- if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
- // Calculate amount of WETH that won't be spent on ETH fees.
- wethSellAmount = getPartialAmountFloor(
- PERCENTAGE_DENOMINATOR,
- safeAdd(PERCENTAGE_DENOMINATOR, feePercentage),
- msg.value
- );
- // Market sell available WETH.
- // ZRX fees are paid with this contract's balance.
- orderFillResults = marketSellWeth(
- orders,
- wethSellAmount,
- signatures
- );
- // The fee amount must be deducted from the amount transfered back to sender.
- makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
- } else {
- // 5% of WETH is reserved for filling feeOrders and paying feeRecipient.
- wethSellAmount = getPartialAmountFloor(
- MAX_WETH_FILL_PERCENTAGE,
- PERCENTAGE_DENOMINATOR,
- msg.value
- );
- // Market sell 95% of WETH.
- // ZRX fees are payed with this contract's balance.
- orderFillResults = marketSellWeth(
- orders,
- wethSellAmount,
- signatures
- );
- // Buy back all ZRX spent on fees.
- zrxBuyAmount = orderFillResults.takerFeePaid;
- feeOrderFillResults = marketBuyExactZrxWithWeth(
- feeOrders,
- zrxBuyAmount,
- feeSignatures
- );
- makerAssetAmountPurchased = orderFillResults.makerAssetFilledAmount;
- }
-
- // Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
- // Refund remaining ETH to msg.sender.
- transferEthFeeAndRefund(
- orderFillResults.takerAssetFilledAmount,
- feeOrderFillResults.takerAssetFilledAmount,
- feePercentage,
- feeRecipient
- );
-
- // Transfer purchased assets to msg.sender.
- transferAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
- }
-
- /// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketBuyOrdersWithEth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- FillResults memory orderFillResults,
- FillResults memory feeOrderFillResults
- )
- {
- // Convert ETH to WETH.
- convertEthToWeth();
-
- uint256 zrxBuyAmount;
- uint256 makerAssetAmountPurchased;
- if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
- // If the makerAsset is ZRX, it is not necessary to pay fees out of this
- // contracts's ZRX balance because fees are factored into the price of the order.
- orderFillResults = marketBuyExactZrxWithWeth(
- orders,
- makerAssetFillAmount,
- signatures
- );
- // The fee amount must be deducted from the amount transfered back to sender.
- makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
- } else {
- // Attemp to purchase desired amount of makerAsset.
- // ZRX fees are payed with this contract's balance.
- orderFillResults = marketBuyExactAmountWithWeth(
- orders,
- makerAssetFillAmount,
- signatures
- );
- // Buy back all ZRX spent on fees.
- zrxBuyAmount = orderFillResults.takerFeePaid;
- feeOrderFillResults = marketBuyExactZrxWithWeth(
- feeOrders,
- zrxBuyAmount,
- feeSignatures
- );
- makerAssetAmountPurchased = orderFillResults.makerAssetFilledAmount;
- }
-
- // Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
- // Refund remaining ETH to msg.sender.
- transferEthFeeAndRefund(
- orderFillResults.takerAssetFilledAmount,
- feeOrderFillResults.takerAssetFilledAmount,
- feePercentage,
- feeRecipient
- );
-
- // Transfer purchased assets to msg.sender.
- transferAssetToSender(orders[0].makerAssetData, makerAssetAmountPurchased);
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol b/packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol
deleted file mode 100644
index d2814a49b..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/MixinWeth.sol
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
- 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 "../../protocol/Exchange/libs/LibMath.sol";
-import "./libs/LibConstants.sol";
-import "./mixins/MWeth.sol";
-
-
-contract MixinWeth is
- LibMath,
- LibConstants,
- MWeth
-{
- /// @dev Default payabale function, this allows us to withdraw WETH
- function ()
- public
- payable
- {
- require(
- msg.sender == address(ETHER_TOKEN),
- "DEFAULT_FUNCTION_WETH_CONTRACT_ONLY"
- );
- }
-
- /// @dev Converts message call's ETH value into WETH.
- function convertEthToWeth()
- internal
- {
- require(
- msg.value > 0,
- "INVALID_MSG_VALUE"
- );
- ETHER_TOKEN.deposit.value(msg.value)();
- }
-
- /// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
- /// Refunds any excess ETH to msg.sender.
- /// @param wethSoldExcludingFeeOrders Amount of WETH sold when filling primary orders.
- /// @param wethSoldForZrx Amount of WETH sold when purchasing ZRX required for primary order fees.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- function transferEthFeeAndRefund(
- uint256 wethSoldExcludingFeeOrders,
- uint256 wethSoldForZrx,
- uint256 feePercentage,
- address feeRecipient
- )
- internal
- {
- // Ensure feePercentage is less than 5%.
- require(
- feePercentage <= MAX_FEE_PERCENTAGE,
- "FEE_PERCENTAGE_TOO_LARGE"
- );
-
- // Ensure that no extra WETH owned by this contract has been sold.
- uint256 wethSold = safeAdd(wethSoldExcludingFeeOrders, wethSoldForZrx);
- require(
- wethSold <= msg.value,
- "OVERSOLD_WETH"
- );
-
- // Calculate amount of WETH that hasn't been sold.
- uint256 wethRemaining = safeSub(msg.value, wethSold);
-
- // Calculate ETH fee to pay to feeRecipient.
- uint256 ethFee = getPartialAmountFloor(
- feePercentage,
- PERCENTAGE_DENOMINATOR,
- wethSoldExcludingFeeOrders
- );
-
- // Ensure fee is less than amount of WETH remaining.
- require(
- ethFee <= wethRemaining,
- "INSUFFICIENT_ETH_REMAINING"
- );
-
- // Do nothing if no WETH remaining
- if (wethRemaining > 0) {
- // Convert remaining WETH to ETH
- ETHER_TOKEN.withdraw(wethRemaining);
-
- // Pay ETH to feeRecipient
- if (ethFee > 0) {
- feeRecipient.transfer(ethFee);
- }
-
- // Refund remaining ETH to msg.sender.
- uint256 ethRefund = safeSub(wethRemaining, ethFee);
- if (ethRefund > 0) {
- msg.sender.transfer(ethRefund);
- }
- }
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol b/packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol
deleted file mode 100644
index 1e034c003..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/interfaces/IAssets.sol
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-
- 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;
-
-
-contract IAssets {
-
- /// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
- /// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
- /// used to withdraw assets that were accidentally sent to this contract.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of ERC20 token to withdraw.
- function withdrawAsset(
- bytes assetData,
- uint256 amount
- )
- external;
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol b/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol
deleted file mode 100644
index f5a26e2ba..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarder.sol
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./IForwarderCore.sol";
-import "./IAssets.sol";
-
-
-// solhint-disable no-empty-blocks
-contract IForwarder is
- IForwarderCore,
- IAssets
-{}
diff --git a/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol b/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol
deleted file mode 100644
index 74c7da01d..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/interfaces/IForwarderCore.sol
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../../protocol/Exchange/libs/LibOrder.sol";
-import "../../../protocol/Exchange/libs/LibFillResults.sol";
-
-
-contract IForwarderCore {
-
- /// @dev Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH).
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketSellOrdersWithEth(
- LibOrder.Order[] memory orders,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- LibFillResults.FillResults memory orderFillResults,
- LibFillResults.FillResults memory feeOrderFillResults
- );
-
- /// @dev Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction.
- /// Any ZRX required to pay fees for primary orders will automatically be purchased by this contract.
- /// Any ETH not spent will be refunded to sender.
- /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
- /// @param makerAssetFillAmount Desired amount of makerAsset to purchase.
- /// @param signatures Proofs that orders have been created by makers.
- /// @param feeOrders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset. Used to purchase ZRX for primary order fees.
- /// @param feeSignatures Proofs that feeOrders have been created by makers.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- /// @return Amounts filled and fees paid by maker and taker for both sets of orders.
- function marketBuyOrdersWithEth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures,
- LibOrder.Order[] memory feeOrders,
- bytes[] memory feeSignatures,
- uint256 feePercentage,
- address feeRecipient
- )
- public
- payable
- returns (
- LibFillResults.FillResults memory orderFillResults,
- LibFillResults.FillResults memory feeOrderFillResults
- );
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol b/packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol
deleted file mode 100644
index 704e42ce3..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/libs/LibConstants.sol
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-
- 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/LibBytes/LibBytes.sol";
-import "../../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../../tokens/EtherToken/IEtherToken.sol";
-import "../../../tokens/ERC20Token/IERC20Token.sol";
-
-
-contract LibConstants {
-
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
- bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
- uint256 constant internal MAX_UINT = 2**256 - 1;
- uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
- uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
- uint256 constant internal MAX_WETH_FILL_PERCENTAGE = 95 * PERCENTAGE_DENOMINATOR / 100; // 95%
-
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
- IEtherToken internal ETHER_TOKEN;
- IERC20Token internal ZRX_TOKEN;
- bytes internal ZRX_ASSET_DATA;
- bytes internal WETH_ASSET_DATA;
- // solhint-enable var-name-mixedcase
-
- constructor (
- address _exchange,
- bytes memory _zrxAssetData,
- bytes memory _wethAssetData
- )
- public
- {
- EXCHANGE = IExchange(_exchange);
- ZRX_ASSET_DATA = _zrxAssetData;
- WETH_ASSET_DATA = _wethAssetData;
-
- address etherToken = _wethAssetData.readAddress(16);
- address zrxToken = _zrxAssetData.readAddress(16);
- ETHER_TOKEN = IEtherToken(etherToken);
- ZRX_TOKEN = IERC20Token(zrxToken);
- }
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol b/packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol
deleted file mode 100644
index fb3ade1db..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/libs/LibForwarderErrors.sol
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-
- 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.
-
-*/
-
-// solhint-disable
-pragma solidity 0.4.24;
-
-
-/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
-contract LibForwarderErrors {
- string constant FEE_PERCENTAGE_TOO_LARGE = "FEE_PROPORTION_TOO_LARGE"; // Provided fee percentage greater than 5%.
- string constant INSUFFICIENT_ETH_REMAINING = "INSUFFICIENT_ETH_REMAINING"; // Not enough ETH remaining to pay feeRecipient.
- string constant OVERSOLD_WETH = "OVERSOLD_WETH"; // More WETH sold than provided with current message call.
- string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired purchase amount not completely filled (required for ZRX fees only).
- string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Asset transfer failed.
- string constant UNSUPPORTED_ASSET_PROXY = "UNSUPPORTED_ASSET_PROXY"; // Proxy in assetData not supported.
- string constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY = "DEFAULT_FUNCTION_WETH_CONTRACT_ONLY"; // Fallback function may only be used for WETH withdrawals.
- string constant INVALID_MSG_VALUE = "INVALID_MSG_VALUE"; // msg.value must be greater than 0.
- string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Amount must equal 1.
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol b/packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol
deleted file mode 100644
index 9e7f80d97..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/mixins/MAssets.sol
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-
- 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 "../interfaces/IAssets.sol";
-
-
-contract MAssets is
- IAssets
-{
- /// @dev Transfers given amount of asset to sender.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of asset to transfer to sender.
- function transferAssetToSender(
- bytes memory assetData,
- uint256 amount
- )
- internal;
-
- /// @dev Decodes ERC20 assetData and transfers given amount to sender.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of asset to transfer to sender.
- function transferERC20Token(
- bytes memory assetData,
- uint256 amount
- )
- internal;
-
- /// @dev Decodes ERC721 assetData and transfers given amount to sender.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param amount Amount of asset to transfer to sender.
- function transferERC721Token(
- bytes memory assetData,
- uint256 amount
- )
- internal;
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol b/packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol
deleted file mode 100644
index 13c26b03a..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/mixins/MExchangeWrapper.sol
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../../protocol/Exchange/libs/LibOrder.sol";
-import "../../../protocol/Exchange/libs/LibFillResults.sol";
-
-
-contract MExchangeWrapper {
-
- /// @dev Fills the input order.
- /// Returns false if the transaction would otherwise revert.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param wethSellAmount Desired amount of WETH to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellWeth(
- LibOrder.Order[] memory orders,
- uint256 wethSellAmount,
- bytes[] memory signatures
- )
- internal
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyExactAmountWithWeth(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- internal
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Buys zrxBuyAmount of ZRX fee tokens, taking into account ZRX fees for each order. This will guarantee
- /// that at least zrxBuyAmount of ZRX is purchased (sometimes slightly over due to rounding issues).
- /// It is possible that a request to buy 200 ZRX will require purchasing 202 ZRX
- /// as 2 ZRX is required to purchase the 200 ZRX fee tokens. This guarantees at least 200 ZRX for future purchases.
- /// The asset being sold by taker must always be WETH.
- /// @param orders Array of order specifications containing ZRX as makerAsset and WETH as takerAsset.
- /// @param zrxBuyAmount Desired amount of ZRX to buy.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return totalFillResults Amounts filled and fees paid by maker and taker.
- function marketBuyExactZrxWithWeth(
- LibOrder.Order[] memory orders,
- uint256 zrxBuyAmount,
- bytes[] memory signatures
- )
- internal
- returns (LibFillResults.FillResults memory totalFillResults);
-}
diff --git a/packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol b/packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol
deleted file mode 100644
index 88e77be4e..000000000
--- a/packages/contracts/contracts/extensions/Forwarder/mixins/MWeth.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
- 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;
-
-
-contract MWeth {
-
- /// @dev Converts message call's ETH value into WETH.
- function convertEthToWeth()
- internal;
-
- /// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
- /// Refunds any excess ETH to msg.sender.
- /// @param wethSoldExcludingFeeOrders Amount of WETH sold when filling primary orders.
- /// @param wethSoldForZrx Amount of WETH sold when purchasing ZRX required for primary order fees.
- /// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
- /// @param feeRecipient Address that will receive ETH when orders are filled.
- function transferEthFeeAndRefund(
- uint256 wethSoldExcludingFeeOrders,
- uint256 wethSoldForZrx,
- uint256 feePercentage,
- address feeRecipient
- )
- internal;
-}
diff --git a/packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol b/packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol
deleted file mode 100644
index 3385d35ef..000000000
--- a/packages/contracts/contracts/extensions/OrderValidator/OrderValidator.sol
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../tokens/ERC20Token/IERC20Token.sol";
-import "../../tokens/ERC721Token/IERC721Token.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-
-
-contract OrderValidator {
-
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
- bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
-
- struct TraderInfo {
- uint256 makerBalance; // Maker's balance of makerAsset
- uint256 makerAllowance; // Maker's allowance to corresponding AssetProxy
- uint256 takerBalance; // Taker's balance of takerAsset
- uint256 takerAllowance; // Taker's allowance to corresponding AssetProxy
- uint256 makerZrxBalance; // Maker's balance of ZRX
- uint256 makerZrxAllowance; // Maker's allowance of ZRX to ERC20Proxy
- uint256 takerZrxBalance; // Taker's balance of ZRX
- uint256 takerZrxAllowance; // Taker's allowance of ZRX to ERC20Proxy
- }
-
- // solhint-disable var-name-mixedcase
- IExchange internal EXCHANGE;
- bytes internal ZRX_ASSET_DATA;
- // solhint-enable var-name-mixedcase
-
- constructor (address _exchange, bytes memory _zrxAssetData)
- public
- {
- EXCHANGE = IExchange(_exchange);
- ZRX_ASSET_DATA = _zrxAssetData;
- }
-
- /// @dev Fetches information for order and maker/taker of order.
- /// @param order The order structure.
- /// @param takerAddress Address that will be filling the order.
- /// @return OrderInfo and TraderInfo instances for given order.
- function getOrderAndTraderInfo(LibOrder.Order memory order, address takerAddress)
- public
- view
- returns (LibOrder.OrderInfo memory orderInfo, TraderInfo memory traderInfo)
- {
- orderInfo = EXCHANGE.getOrderInfo(order);
- traderInfo = getTraderInfo(order, takerAddress);
- return (orderInfo, traderInfo);
- }
-
- /// @dev Fetches information for all passed in orders and the makers/takers of each order.
- /// @param orders Array of order specifications.
- /// @param takerAddresses Array of taker addresses corresponding to each order.
- /// @return Arrays of OrderInfo and TraderInfo instances that correspond to each order.
- function getOrdersAndTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
- public
- view
- returns (LibOrder.OrderInfo[] memory ordersInfo, TraderInfo[] memory tradersInfo)
- {
- ordersInfo = EXCHANGE.getOrdersInfo(orders);
- tradersInfo = getTradersInfo(orders, takerAddresses);
- return (ordersInfo, tradersInfo);
- }
-
- /// @dev Fetches balance and allowances for maker and taker of order.
- /// @param order The order structure.
- /// @param takerAddress Address that will be filling the order.
- /// @return Balances and allowances of maker and taker of order.
- function getTraderInfo(LibOrder.Order memory order, address takerAddress)
- public
- view
- returns (TraderInfo memory traderInfo)
- {
- (traderInfo.makerBalance, traderInfo.makerAllowance) = getBalanceAndAllowance(order.makerAddress, order.makerAssetData);
- (traderInfo.takerBalance, traderInfo.takerAllowance) = getBalanceAndAllowance(takerAddress, order.takerAssetData);
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- (traderInfo.makerZrxBalance, traderInfo.makerZrxAllowance) = getBalanceAndAllowance(order.makerAddress, zrxAssetData);
- (traderInfo.takerZrxBalance, traderInfo.takerZrxAllowance) = getBalanceAndAllowance(takerAddress, zrxAssetData);
- return traderInfo;
- }
-
- /// @dev Fetches balances and allowances of maker and taker for each provided order.
- /// @param orders Array of order specifications.
- /// @param takerAddresses Array of taker addresses corresponding to each order.
- /// @return Array of balances and allowances for maker and taker of each order.
- function getTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
- public
- view
- returns (TraderInfo[] memory)
- {
- uint256 ordersLength = orders.length;
- TraderInfo[] memory tradersInfo = new TraderInfo[](ordersLength);
- for (uint256 i = 0; i != ordersLength; i++) {
- tradersInfo[i] = getTraderInfo(orders[i], takerAddresses[i]);
- }
- return tradersInfo;
- }
-
- /// @dev Fetches token balances and allowances of an address to given assetProxy. Supports ERC20 and ERC721.
- /// @param target Address to fetch balances and allowances of.
- /// @param assetData Encoded data that can be decoded by a specified proxy contract when transferring asset.
- /// @return Balance of asset and allowance set to given proxy of asset.
- /// For ERC721 tokens, these values will always be 1 or 0.
- function getBalanceAndAllowance(address target, bytes memory assetData)
- public
- view
- returns (uint256 balance, uint256 allowance)
- {
- bytes4 assetProxyId = assetData.readBytes4(0);
- address token = assetData.readAddress(16);
- address assetProxy = EXCHANGE.getAssetProxy(assetProxyId);
-
- if (assetProxyId == ERC20_DATA_ID) {
- // Query balance
- balance = IERC20Token(token).balanceOf(target);
-
- // Query allowance
- allowance = IERC20Token(token).allowance(target, assetProxy);
- } else if (assetProxyId == ERC721_DATA_ID) {
- uint256 tokenId = assetData.readUint256(36);
-
- // Query owner of tokenId
- address owner = getERC721TokenOwner(token, tokenId);
-
- // Set balance to 1 if tokenId is owned by target
- balance = target == owner ? 1 : 0;
-
- // Check if ERC721Proxy is approved to spend tokenId
- bool isApproved = IERC721Token(token).isApprovedForAll(target, assetProxy);
-
- // Set alowance to 1 if ERC721Proxy is approved to spend tokenId
- allowance = isApproved ? 1 : 0;
- } else {
- revert("UNSUPPORTED_ASSET_PROXY");
- }
- return (balance, allowance);
- }
-
- /// @dev Fetches token balances and allowances of an address for each given assetProxy. Supports ERC20 and ERC721.
- /// @param target Address to fetch balances and allowances of.
- /// @param assetData Array of encoded byte arrays that can be decoded by a specified proxy contract when transferring asset.
- /// @return Balances and allowances of assets.
- /// For ERC721 tokens, these values will always be 1 or 0.
- function getBalancesAndAllowances(address target, bytes[] memory assetData)
- public
- view
- returns (uint256[] memory, uint256[] memory)
- {
- uint256 length = assetData.length;
- uint256[] memory balances = new uint256[](length);
- uint256[] memory allowances = new uint256[](length);
- for (uint256 i = 0; i != length; i++) {
- (balances[i], allowances[i]) = getBalanceAndAllowance(target, assetData[i]);
- }
- return (balances, allowances);
- }
-
- /// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
- /// @param token Address of ERC721 token.
- /// @param tokenId The identifier for the specific NFT.
- /// @return Owner of tokenId or null address if unowned.
- function getERC721TokenOwner(address token, uint256 tokenId)
- public
- view
- returns (address owner)
- {
- assembly {
- // load free memory pointer
- let cdStart := mload(64)
-
- // bytes4(keccak256(ownerOf(uint256))) = 0x6352211e
- mstore(cdStart, 0x6352211e00000000000000000000000000000000000000000000000000000000)
- mstore(add(cdStart, 4), tokenId)
-
- // staticcall `ownerOf(tokenId)`
- // `ownerOf` will revert if tokenId is not owned
- let success := staticcall(
- gas, // forward all gas
- token, // call token contract
- cdStart, // start of calldata
- 36, // length of input is 36 bytes
- cdStart, // write output over input
- 32 // size of output is 32 bytes
- )
-
- // Success implies that tokenId is owned
- // Copy owner from return data if successful
- if success {
- owner := mload(cdStart)
- }
- }
-
- // Owner initialized to address(0), no need to modify if call is unsuccessful
- return owner;
- }
-}
diff --git a/packages/contracts/contracts/multisig/MultiSigWallet.sol b/packages/contracts/contracts/multisig/MultiSigWallet.sol
deleted file mode 100644
index 516e7391c..000000000
--- a/packages/contracts/contracts/multisig/MultiSigWallet.sol
+++ /dev/null
@@ -1,393 +0,0 @@
-// solhint-disable
-pragma solidity ^0.4.15;
-
-
-/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
-/// @author Stefan George - <stefan.george@consensys.net>
-contract MultiSigWallet {
-
- /*
- * Events
- */
- event Confirmation(address indexed sender, uint indexed transactionId);
- event Revocation(address indexed sender, uint indexed transactionId);
- event Submission(uint indexed transactionId);
- event Execution(uint indexed transactionId);
- event ExecutionFailure(uint indexed transactionId);
- event Deposit(address indexed sender, uint value);
- event OwnerAddition(address indexed owner);
- event OwnerRemoval(address indexed owner);
- event RequirementChange(uint required);
-
- /*
- * Constants
- */
- uint constant public MAX_OWNER_COUNT = 50;
-
- /*
- * Storage
- */
- mapping (uint => Transaction) public transactions;
- mapping (uint => mapping (address => bool)) public confirmations;
- mapping (address => bool) public isOwner;
- address[] public owners;
- uint public required;
- uint public transactionCount;
-
- struct Transaction {
- address destination;
- uint value;
- bytes data;
- bool executed;
- }
-
- /*
- * Modifiers
- */
- modifier onlyWallet() {
- require(msg.sender == address(this));
- _;
- }
-
- modifier ownerDoesNotExist(address owner) {
- require(!isOwner[owner]);
- _;
- }
-
- modifier ownerExists(address owner) {
- require(isOwner[owner]);
- _;
- }
-
- modifier transactionExists(uint transactionId) {
- require(transactions[transactionId].destination != 0);
- _;
- }
-
- modifier confirmed(uint transactionId, address owner) {
- require(confirmations[transactionId][owner]);
- _;
- }
-
- modifier notConfirmed(uint transactionId, address owner) {
- require(!confirmations[transactionId][owner]);
- _;
- }
-
- modifier notExecuted(uint transactionId) {
- require(!transactions[transactionId].executed);
- _;
- }
-
- modifier notNull(address _address) {
- require(_address != 0);
- _;
- }
-
- modifier validRequirement(uint ownerCount, uint _required) {
- require(ownerCount <= MAX_OWNER_COUNT
- && _required <= ownerCount
- && _required != 0
- && ownerCount != 0);
- _;
- }
-
- /// @dev Fallback function allows to deposit ether.
- function()
- payable
- {
- if (msg.value > 0)
- Deposit(msg.sender, msg.value);
- }
-
- /*
- * Public functions
- */
- /// @dev Contract constructor sets initial owners and required number of confirmations.
- /// @param _owners List of initial owners.
- /// @param _required Number of required confirmations.
- function MultiSigWallet(address[] _owners, uint _required)
- public
- validRequirement(_owners.length, _required)
- {
- for (uint i=0; i<_owners.length; i++) {
- require(!isOwner[_owners[i]] && _owners[i] != 0);
- isOwner[_owners[i]] = true;
- }
- owners = _owners;
- required = _required;
- }
-
- /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
- /// @param owner Address of new owner.
- function addOwner(address owner)
- public
- onlyWallet
- ownerDoesNotExist(owner)
- notNull(owner)
- validRequirement(owners.length + 1, required)
- {
- isOwner[owner] = true;
- owners.push(owner);
- OwnerAddition(owner);
- }
-
- /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
- /// @param owner Address of owner.
- function removeOwner(address owner)
- public
- onlyWallet
- ownerExists(owner)
- {
- isOwner[owner] = false;
- for (uint i=0; i<owners.length - 1; i++)
- if (owners[i] == owner) {
- owners[i] = owners[owners.length - 1];
- break;
- }
- owners.length -= 1;
- if (required > owners.length)
- changeRequirement(owners.length);
- OwnerRemoval(owner);
- }
-
- /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
- /// @param owner Address of owner to be replaced.
- /// @param newOwner Address of new owner.
- function replaceOwner(address owner, address newOwner)
- public
- onlyWallet
- ownerExists(owner)
- ownerDoesNotExist(newOwner)
- {
- for (uint i=0; i<owners.length; i++)
- if (owners[i] == owner) {
- owners[i] = newOwner;
- break;
- }
- isOwner[owner] = false;
- isOwner[newOwner] = true;
- OwnerRemoval(owner);
- OwnerAddition(newOwner);
- }
-
- /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
- /// @param _required Number of required confirmations.
- function changeRequirement(uint _required)
- public
- onlyWallet
- validRequirement(owners.length, _required)
- {
- required = _required;
- RequirementChange(_required);
- }
-
- /// @dev Allows an owner to submit and confirm a transaction.
- /// @param destination Transaction target address.
- /// @param value Transaction ether value.
- /// @param data Transaction data payload.
- /// @return Returns transaction ID.
- function submitTransaction(address destination, uint value, bytes data)
- public
- returns (uint transactionId)
- {
- transactionId = addTransaction(destination, value, data);
- confirmTransaction(transactionId);
- }
-
- /// @dev Allows an owner to confirm a transaction.
- /// @param transactionId Transaction ID.
- function confirmTransaction(uint transactionId)
- public
- ownerExists(msg.sender)
- transactionExists(transactionId)
- notConfirmed(transactionId, msg.sender)
- {
- confirmations[transactionId][msg.sender] = true;
- Confirmation(msg.sender, transactionId);
- executeTransaction(transactionId);
- }
-
- /// @dev Allows an owner to revoke a confirmation for a transaction.
- /// @param transactionId Transaction ID.
- function revokeConfirmation(uint transactionId)
- public
- ownerExists(msg.sender)
- confirmed(transactionId, msg.sender)
- notExecuted(transactionId)
- {
- confirmations[transactionId][msg.sender] = false;
- Revocation(msg.sender, transactionId);
- }
-
- /// @dev Allows anyone to execute a confirmed transaction.
- /// @param transactionId Transaction ID.
- function executeTransaction(uint transactionId)
- public
- ownerExists(msg.sender)
- confirmed(transactionId, msg.sender)
- notExecuted(transactionId)
- {
- if (isConfirmed(transactionId)) {
- Transaction storage txn = transactions[transactionId];
- txn.executed = true;
- if (external_call(txn.destination, txn.value, txn.data.length, txn.data))
- Execution(transactionId);
- else {
- ExecutionFailure(transactionId);
- txn.executed = false;
- }
- }
- }
-
- // call has been separated into its own function in order to take advantage
- // of the Solidity's code generator to produce a loop that copies tx.data into memory.
- function external_call(address destination, uint value, uint dataLength, bytes data) internal returns (bool) {
- bool result;
- assembly {
- let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
- let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
- result := call(
- sub(gas, 34710), // 34710 is the value that solidity is currently emitting
- // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
- // callNewAccountGas (25000, in case the destination address does not exist and needs creating)
- destination,
- value,
- d,
- dataLength, // Size of the input (in bytes) - this is what fixes the padding problem
- x,
- 0 // Output is ignored, therefore the output size is zero
- )
- }
- return result;
- }
-
- /// @dev Returns the confirmation status of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Confirmation status.
- function isConfirmed(uint transactionId)
- public
- constant
- returns (bool)
- {
- uint count = 0;
- for (uint i=0; i<owners.length; i++) {
- if (confirmations[transactionId][owners[i]])
- count += 1;
- if (count == required)
- return true;
- }
- }
-
- /*
- * Internal functions
- */
- /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
- /// @param destination Transaction target address.
- /// @param value Transaction ether value.
- /// @param data Transaction data payload.
- /// @return Returns transaction ID.
- function addTransaction(address destination, uint value, bytes data)
- internal
- notNull(destination)
- returns (uint transactionId)
- {
- transactionId = transactionCount;
- transactions[transactionId] = Transaction({
- destination: destination,
- value: value,
- data: data,
- executed: false
- });
- transactionCount += 1;
- Submission(transactionId);
- }
-
- /*
- * Web3 call functions
- */
- /// @dev Returns number of confirmations of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Number of confirmations.
- function getConfirmationCount(uint transactionId)
- public
- constant
- returns (uint count)
- {
- for (uint i=0; i<owners.length; i++)
- if (confirmations[transactionId][owners[i]])
- count += 1;
- }
-
- /// @dev Returns total number of transactions after filers are applied.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Total number of transactions after filters are applied.
- function getTransactionCount(bool pending, bool executed)
- public
- constant
- returns (uint count)
- {
- for (uint i=0; i<transactionCount; i++)
- if ( pending && !transactions[i].executed
- || executed && transactions[i].executed)
- count += 1;
- }
-
- /// @dev Returns list of owners.
- /// @return List of owner addresses.
- function getOwners()
- public
- constant
- returns (address[])
- {
- return owners;
- }
-
- /// @dev Returns array with owner addresses, which confirmed transaction.
- /// @param transactionId Transaction ID.
- /// @return Returns array of owner addresses.
- function getConfirmations(uint transactionId)
- public
- constant
- returns (address[] _confirmations)
- {
- address[] memory confirmationsTemp = new address[](owners.length);
- uint count = 0;
- uint i;
- for (i=0; i<owners.length; i++)
- if (confirmations[transactionId][owners[i]]) {
- confirmationsTemp[count] = owners[i];
- count += 1;
- }
- _confirmations = new address[](count);
- for (i=0; i<count; i++)
- _confirmations[i] = confirmationsTemp[i];
- }
-
- /// @dev Returns list of transaction IDs in defined range.
- /// @param from Index start position of transaction array.
- /// @param to Index end position of transaction array.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Returns array of transaction IDs.
- function getTransactionIds(uint from, uint to, bool pending, bool executed)
- public
- constant
- returns (uint[] _transactionIds)
- {
- uint[] memory transactionIdsTemp = new uint[](transactionCount);
- uint count = 0;
- uint i;
- for (i=0; i<transactionCount; i++)
- if ( pending && !transactions[i].executed
- || executed && transactions[i].executed)
- {
- transactionIdsTemp[count] = i;
- count += 1;
- }
- _transactionIds = new uint[](to - from);
- for (i=from; i<to; i++)
- _transactionIds[i - from] = transactionIdsTemp[i];
- }
-} \ No newline at end of file
diff --git a/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol
deleted file mode 100644
index 9513d3b30..000000000
--- a/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-
- 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 "./MultiSigWallet.sol";
-
-
-/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
-/// @author Amir Bandeali - <amir@0xProject.com>
-// solhint-disable not-rely-on-time
-contract MultiSigWalletWithTimeLock is
- MultiSigWallet
-{
- event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime);
- event TimeLockChange(uint256 secondsTimeLocked);
-
- uint256 public secondsTimeLocked;
-
- mapping (uint256 => uint256) public confirmationTimes;
-
- modifier notFullyConfirmed(uint256 transactionId) {
- require(
- !isConfirmed(transactionId),
- "TX_FULLY_CONFIRMED"
- );
- _;
- }
-
- modifier fullyConfirmed(uint256 transactionId) {
- require(
- isConfirmed(transactionId),
- "TX_NOT_FULLY_CONFIRMED"
- );
- _;
- }
-
- modifier pastTimeLock(uint256 transactionId) {
- require(
- block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked,
- "TIME_LOCK_INCOMPLETE"
- );
- _;
- }
-
- /// @dev Contract constructor sets initial owners, required number of confirmations, and time lock.
- /// @param _owners List of initial owners.
- /// @param _required Number of required confirmations.
- /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
- constructor (
- address[] _owners,
- uint256 _required,
- uint256 _secondsTimeLocked
- )
- public
- MultiSigWallet(_owners, _required)
- {
- secondsTimeLocked = _secondsTimeLocked;
- }
-
- /// @dev Changes the duration of the time lock for transactions.
- /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
- function changeTimeLock(uint256 _secondsTimeLocked)
- public
- onlyWallet
- {
- secondsTimeLocked = _secondsTimeLocked;
- emit TimeLockChange(_secondsTimeLocked);
- }
-
- /// @dev Allows an owner to confirm a transaction.
- /// @param transactionId Transaction ID.
- function confirmTransaction(uint256 transactionId)
- public
- ownerExists(msg.sender)
- transactionExists(transactionId)
- notConfirmed(transactionId, msg.sender)
- notFullyConfirmed(transactionId)
- {
- confirmations[transactionId][msg.sender] = true;
- emit Confirmation(msg.sender, transactionId);
- if (isConfirmed(transactionId)) {
- setConfirmationTime(transactionId, block.timestamp);
- }
- }
-
- /// @dev Allows anyone to execute a confirmed transaction.
- /// @param transactionId Transaction ID.
- function executeTransaction(uint256 transactionId)
- public
- notExecuted(transactionId)
- fullyConfirmed(transactionId)
- pastTimeLock(transactionId)
- {
- Transaction storage txn = transactions[transactionId];
- txn.executed = true;
- if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) {
- emit Execution(transactionId);
- } else {
- emit ExecutionFailure(transactionId);
- txn.executed = false;
- }
- }
-
- /// @dev Sets the time of when a submission first passed.
- function setConfirmationTime(uint256 transactionId, uint256 confirmationTime)
- internal
- {
- confirmationTimes[transactionId] = confirmationTime;
- emit ConfirmationTimeSet(transactionId, confirmationTime);
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol b/packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol
deleted file mode 100644
index 258443bca..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/ERC20Proxy.sol
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
-
- 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 "./MixinAuthorizable.sol";
-
-
-contract ERC20Proxy is
- MixinAuthorizable
-{
- // Id of this proxy.
- bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
-
- // 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
- let start := mload(64)
- mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(start, 32), authorized_slot)
-
- // Revert if authorized[msg.sender] == false
- if iszero(sload(keccak256(start, 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.
-
- // Asset data itself is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 1 * 32 | function parameters: |
- // | | 4 | 12 + 20 | 1. token address |
-
- // We construct calldata for the `token.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 4 | | 1. from |
- // | | 36 | | 2. to |
- // | | 68 | | 3. amount |
-
- /////// Read token address from calldata ///////
- // * The token address is stored in `assetData`.
- //
- // * The "offset to assetData" is stored at offset 4 in the calldata (table 1).
- // [assetDataOffsetFromParams = calldataload(4)]
- //
- // * Notes that the "offset to assetData" is relative to the "Params" area of calldata;
- // add 4 bytes to account for the length of the "Header" area (table 1).
- // [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4]
- //
- // * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
- // [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
- let token := calldataload(add(calldataload(4), 40))
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFrom` selector.
- // Any trailing data in transferFromSelector will be
- // overwritten in the next `mstore` call.
- mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // We copy the fields `from`, `to` and `amount` in bulk
- // from our own calldata to the new calldata.
- calldatacopy(4, 36, 96)
-
- /////// Call `token.transferFrom` using the calldata ///////
- let success := call(
- gas, // forward all gas
- token, // call address of token contract
- 0, // don't send any ETH
- 0, // pointer to start of input
- 100, // length of input
- 0, // write output over input
- 32 // output size should be 32 bytes
- )
-
- /////// Check return data. ///////
- // If there is no return data, we assume the token incorrectly
- // does not return a bool. In this case we expect it to revert
- // on failure, which was handled above.
- // If the token does return data, we require that it is a single
- // nonzero 32 bytes value.
- // So the transfer succeeded if the call succeeded and either
- // returned nothing, or returned a non-zero 32 byte value.
- success := and(success, or(
- iszero(returndatasize),
- and(
- eq(returndatasize, 32),
- gt(mload(0), 0)
- )
- ))
- if success {
- return(0, 0)
- }
-
- // Revert with `Error("TRANSFER_FAILED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // 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;
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol b/packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol
deleted file mode 100644
index 65b664b8b..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/ERC721Proxy.sol
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-
- 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 "./MixinAuthorizable.sol";
-
-
-contract ERC721Proxy is
- MixinAuthorizable
-{
- // Id of this proxy.
- bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
-
- // 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
- let start := mload(64)
- mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(start, 32), authorized_slot)
-
- // Revert if authorized[msg.sender] == false
- if iszero(sload(keccak256(start, 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.
-
- // Asset data itself is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 2 * 32 | function parameters: |
- // | | 4 | 12 + 20 | 1. token address |
- // | | 36 | | 2. tokenId |
-
- // We construct calldata for the `token.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 4 | | 1. from |
- // | | 36 | | 2. to |
- // | | 68 | | 3. tokenId |
-
- // There exists only 1 of each token.
- // require(amount == 1, "INVALID_AMOUNT")
- if sub(calldataload(100), 1) {
- // Revert with `Error("INVALID_AMOUNT")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFrom` selector.
- // Any trailing data in transferFromSelector will be
- // overwritten in the next `mstore` call.
- mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // We copy the fields `from` and `to` in bulk
- // from our own calldata to the new calldata.
- calldatacopy(4, 36, 64)
-
- // Copy `tokenId` field from our own calldata to the new calldata.
- let assetDataOffset := calldataload(4)
- calldatacopy(68, add(assetDataOffset, 72), 32)
-
- /////// Call `token.transferFrom` using the calldata ///////
- let token := calldataload(add(assetDataOffset, 40))
- let success := call(
- gas, // forward all gas
- token, // call address of token contract
- 0, // don't send any ETH
- 0, // pointer to start of input
- 100, // length of input
- 0, // write output to null
- 0 // output size is 0 bytes
- )
- if success {
- return(0, 0)
- }
-
- // Revert with `Error("TRANSFER_FAILED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // 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;
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol b/packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol
deleted file mode 100644
index fe9bbf848..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/MixinAuthorizable.sol
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-
- 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/Ownable/Ownable.sol";
-import "./mixins/MAuthorizable.sol";
-
-
-contract MixinAuthorizable is
- Ownable,
- MAuthorizable
-{
- /// @dev Only authorized addresses can invoke functions with this modifier.
- modifier onlyAuthorized {
- require(
- authorized[msg.sender],
- "SENDER_NOT_AUTHORIZED"
- );
- _;
- }
-
- mapping (address => bool) public authorized;
- address[] public authorities;
-
- /// @dev Authorizes an address.
- /// @param target Address to authorize.
- function addAuthorizedAddress(address target)
- external
- onlyOwner
- {
- require(
- !authorized[target],
- "TARGET_ALREADY_AUTHORIZED"
- );
-
- authorized[target] = true;
- authorities.push(target);
- emit AuthorizedAddressAdded(target, msg.sender);
- }
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- function removeAuthorizedAddress(address target)
- external
- onlyOwner
- {
- require(
- authorized[target],
- "TARGET_NOT_AUTHORIZED"
- );
-
- delete authorized[target];
- for (uint256 i = 0; i < authorities.length; i++) {
- if (authorities[i] == target) {
- authorities[i] = authorities[authorities.length - 1];
- authorities.length -= 1;
- break;
- }
- }
- emit AuthorizedAddressRemoved(target, msg.sender);
- }
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- /// @param index Index of target in authorities array.
- function removeAuthorizedAddressAtIndex(
- address target,
- uint256 index
- )
- external
- onlyOwner
- {
- require(
- authorized[target],
- "TARGET_NOT_AUTHORIZED"
- );
- require(
- index < authorities.length,
- "INDEX_OUT_OF_BOUNDS"
- );
- require(
- authorities[index] == target,
- "AUTHORIZED_ADDRESS_MISMATCH"
- );
-
- delete authorized[target];
- authorities[index] = authorities[authorities.length - 1];
- authorities.length -= 1;
- emit AuthorizedAddressRemoved(target, msg.sender);
- }
-
- /// @dev Gets all authorized addresses.
- /// @return Array of authorized addresses.
- function getAuthorizedAddresses()
- external
- view
- returns (address[] memory)
- {
- return authorities;
- }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
deleted file mode 100644
index 3e76e38dd..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetData.sol
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-
- 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.
-
-*/
-
-// solhint-disable
-pragma solidity 0.4.24;
-
-
-// @dev Interface of the asset proxy's assetData.
-// The asset proxies take an ABI encoded `bytes assetData` as argument.
-// This argument is ABI encoded as one of the methods of this interface.
-interface IAssetData {
-
- function ERC20Token(address tokenContract)
- external
- pure;
-
- function ERC721Token(
- address tokenContract,
- uint256 tokenId,
- bytes receiverData
- )
- external
- pure;
-
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol
deleted file mode 100644
index b25d2d75a..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAssetProxy.sol
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-
- 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 "./IAuthorizable.sol";
-
-
-contract IAssetProxy is
- IAuthorizable
-{
- /// @dev Transfers assets. Either succeeds or throws.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param from Address to transfer asset from.
- /// @param to Address to transfer asset to.
- /// @param amount Amount of asset to transfer.
- function transferFrom(
- bytes assetData,
- address from,
- address to,
- uint256 amount
- )
- external;
-
- /// @dev Gets the proxy id associated with the proxy address.
- /// @return Proxy id.
- function getProxyId()
- external
- pure
- returns (bytes4);
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol b/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol
deleted file mode 100644
index ba1d4aa77..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/interfaces/IAuthorizable.sol
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-
- 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/Ownable/IOwnable.sol";
-
-
-contract IAuthorizable is
- IOwnable
-{
- /// @dev Authorizes an address.
- /// @param target Address to authorize.
- function addAuthorizedAddress(address target)
- external;
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- function removeAuthorizedAddress(address target)
- external;
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- /// @param index Index of target in authorities array.
- function removeAuthorizedAddressAtIndex(
- address target,
- uint256 index
- )
- external;
-
- /// @dev Gets all authorized addresses.
- /// @return Array of authorized addresses.
- function getAuthorizedAddresses()
- external
- view
- returns (address[] memory);
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol b/packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
deleted file mode 100644
index 1d9a70cc1..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
- 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.
-
-*/
-
-// solhint-disable
-pragma solidity 0.4.24;
-
-
-/// @dev This contract documents the revert reasons used in the AssetProxy contracts.
-/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
-contract LibAssetProxyErrors {
-
- /// Authorizable errors ///
- string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED"; // Sender not authorized to call this method.
- string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED"; // Target address not authorized to call this method.
- string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED"; // Target address must not already be authorized.
- string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS"; // Specified array index is out of bounds.
- string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH"; // Address at index does not match given target address.
-
- /// Transfer errors ///
- string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
- string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
- string constant LENGTH_GREATER_THAN_131_REQUIRED = "LENGTH_GREATER_THAN_131_REQUIRED"; // Byte array must have a length greater than 0.
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol b/packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol
deleted file mode 100644
index d63fb7f6d..000000000
--- a/packages/contracts/contracts/protocol/AssetProxy/mixins/MAuthorizable.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
- 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 "../interfaces/IAuthorizable.sol";
-
-
-contract MAuthorizable is
- IAuthorizable
-{
- // Event logged when a new address is authorized.
- event AuthorizedAddressAdded(
- address indexed target,
- address indexed caller
- );
-
- // Event logged when a currently authorized address is unauthorized.
- event AuthorizedAddressRemoved(
- address indexed target,
- address indexed caller
- );
-
- /// @dev Only authorized addresses can invoke functions with this modifier.
- modifier onlyAuthorized { revert(); _; }
-}
diff --git a/packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol b/packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol
deleted file mode 100644
index edb788fab..000000000
--- a/packages/contracts/contracts/protocol/AssetProxyOwner/AssetProxyOwner.sol
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-
- 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 "../../multisig/MultiSigWalletWithTimeLock.sol";
-import "../../utils/LibBytes/LibBytes.sol";
-
-
-contract AssetProxyOwner is
- MultiSigWalletWithTimeLock
-{
- using LibBytes for bytes;
-
- event AssetProxyRegistration(address assetProxyContract, bool isRegistered);
-
- // Mapping of AssetProxy contract address =>
- // if this contract is allowed to call the AssetProxy's `removeAuthorizedAddressAtIndex` method without a time lock.
- mapping (address => bool) public isAssetProxyRegistered;
-
- bytes4 constant internal REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR = bytes4(keccak256("removeAuthorizedAddressAtIndex(address,uint256)"));
-
- /// @dev Function will revert if the transaction does not call `removeAuthorizedAddressAtIndex`
- /// on an approved AssetProxy contract.
- modifier validRemoveAuthorizedAddressAtIndexTx(uint256 transactionId) {
- Transaction storage txn = transactions[transactionId];
- require(
- isAssetProxyRegistered[txn.destination],
- "UNREGISTERED_ASSET_PROXY"
- );
- require(
- txn.data.readBytes4(0) == REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR,
- "INVALID_FUNCTION_SELECTOR"
- );
- _;
- }
-
- /// @dev Contract constructor sets initial owners, required number of confirmations,
- /// time lock, and list of AssetProxy addresses.
- /// @param _owners List of initial owners.
- /// @param _assetProxyContracts Array of AssetProxy contract addresses.
- /// @param _required Number of required confirmations.
- /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
- constructor (
- address[] memory _owners,
- address[] memory _assetProxyContracts,
- uint256 _required,
- uint256 _secondsTimeLocked
- )
- public
- MultiSigWalletWithTimeLock(_owners, _required, _secondsTimeLocked)
- {
- for (uint256 i = 0; i < _assetProxyContracts.length; i++) {
- address assetProxy = _assetProxyContracts[i];
- require(
- assetProxy != address(0),
- "INVALID_ASSET_PROXY"
- );
- isAssetProxyRegistered[assetProxy] = true;
- }
- }
-
- /// @dev Registers or deregisters an AssetProxy to be able to execute
- /// `removeAuthorizedAddressAtIndex` without a timelock.
- /// @param assetProxyContract Address of AssetProxy contract.
- /// @param isRegistered Status of approval for AssetProxy contract.
- function registerAssetProxy(address assetProxyContract, bool isRegistered)
- public
- onlyWallet
- notNull(assetProxyContract)
- {
- isAssetProxyRegistered[assetProxyContract] = isRegistered;
- emit AssetProxyRegistration(assetProxyContract, isRegistered);
- }
-
- /// @dev Allows execution of `removeAuthorizedAddressAtIndex` without time lock.
- /// @param transactionId Transaction ID.
- function executeRemoveAuthorizedAddressAtIndex(uint256 transactionId)
- public
- notExecuted(transactionId)
- fullyConfirmed(transactionId)
- validRemoveAuthorizedAddressAtIndexTx(transactionId)
- {
- Transaction storage txn = transactions[transactionId];
- txn.executed = true;
- if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) {
- emit Execution(transactionId);
- } else {
- emit ExecutionFailure(transactionId);
- txn.executed = false;
- }
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/Exchange.sol b/packages/contracts/contracts/protocol/Exchange/Exchange.sol
deleted file mode 100644
index ead36009f..000000000
--- a/packages/contracts/contracts/protocol/Exchange/Exchange.sol
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./libs/LibConstants.sol";
-import "./MixinExchangeCore.sol";
-import "./MixinSignatureValidator.sol";
-import "./MixinWrapperFunctions.sol";
-import "./MixinAssetProxyDispatcher.sol";
-import "./MixinTransactions.sol";
-import "./MixinMatchOrders.sol";
-
-
-// solhint-disable no-empty-blocks
-contract Exchange is
- MixinExchangeCore,
- MixinMatchOrders,
- MixinSignatureValidator,
- MixinTransactions,
- MixinAssetProxyDispatcher,
- MixinWrapperFunctions
-{
- string constant public VERSION = "2.0.1-alpha";
-
- // Mixins are instantiated in the order they are inherited
- constructor (bytes memory _zrxAssetData)
- public
- LibConstants(_zrxAssetData) // @TODO: Remove when we deploy.
- MixinExchangeCore()
- MixinMatchOrders()
- MixinSignatureValidator()
- MixinTransactions()
- MixinAssetProxyDispatcher()
- MixinWrapperFunctions()
- {}
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol b/packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
deleted file mode 100644
index 87b09b6b3..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
-
- 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/Ownable/Ownable.sol";
-import "./mixins/MAssetProxyDispatcher.sol";
-import "../AssetProxy/interfaces/IAssetProxy.sol";
-
-
-contract MixinAssetProxyDispatcher is
- Ownable,
- MAssetProxyDispatcher
-{
- // Mapping from Asset Proxy Id's to their respective Asset Proxy
- mapping (bytes4 => IAssetProxy) public assetProxies;
-
- /// @dev Registers an asset proxy to its asset proxy id.
- /// Once an asset proxy is registered, it cannot be unregistered.
- /// @param assetProxy Address of new asset proxy to register.
- function registerAssetProxy(address assetProxy)
- external
- onlyOwner
- {
- IAssetProxy assetProxyContract = IAssetProxy(assetProxy);
-
- // Ensure that no asset proxy exists with current id.
- bytes4 assetProxyId = assetProxyContract.getProxyId();
- address currentAssetProxy = assetProxies[assetProxyId];
- require(
- currentAssetProxy == address(0),
- "ASSET_PROXY_ALREADY_EXISTS"
- );
-
- // Add asset proxy and log registration.
- assetProxies[assetProxyId] = assetProxyContract;
- emit AssetProxyRegistered(
- assetProxyId,
- assetProxy
- );
- }
-
- /// @dev Gets an asset proxy.
- /// @param assetProxyId Id of the asset proxy.
- /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
- function getAssetProxy(bytes4 assetProxyId)
- external
- view
- returns (address)
- {
- return assetProxies[assetProxyId];
- }
-
- /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetData Byte array encoded for the asset.
- /// @param from Address to transfer token from.
- /// @param to Address to transfer token to.
- /// @param amount Amount of token to transfer.
- function dispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- internal
- {
- // Do nothing if no amount should be transferred.
- if (amount > 0 && from != to) {
- // Ensure assetData length is valid
- require(
- assetData.length > 3,
- "LENGTH_GREATER_THAN_3_REQUIRED"
- );
-
- // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
- bytes4 assetProxyId;
- assembly {
- assetProxyId := and(mload(
- add(assetData, 32)),
- 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
- )
- }
- address assetProxy = assetProxies[assetProxyId];
-
- // Ensure that assetProxy exists
- require(
- assetProxy != address(0),
- "ASSET_PROXY_DOES_NOT_EXIST"
- );
-
- // We construct calldata for the `assetProxy.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | 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 |
-
- assembly {
- /////// Setup State ///////
- // `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr).
- let cdStart := mload(64)
- // `dataAreaLength` is the total number of words needed to store `assetData`
- // As-per the ABI spec, this value is padded up to the nearest multiple of 32,
- // and includes 32-bytes for length.
- let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0)
- // `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
- let cdEnd := add(cdStart, add(132, dataAreaLength))
-
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFromSelector`.
- // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
- mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
- // Notes:
- // 1. The offset to `assetData` is the length of the Params Area (128 bytes).
- // 2. A 20-byte mask is applied to addresses to zero-out the unused bytes.
- mstore(add(cdStart, 4), 128)
- mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(cdStart, 100), amount)
-
- /////// Setup Data Area ///////
- // This area holds `assetData`.
- let dataArea := add(cdStart, 132)
- // solhint-disable-next-line no-empty-blocks
- for {} lt(dataArea, cdEnd) {} {
- mstore(dataArea, mload(assetData))
- dataArea := add(dataArea, 32)
- assetData := add(assetData, 32)
- }
-
- /////// Call `assetProxy.transferFrom` using the constructed calldata ///////
- let success := call(
- gas, // forward all gas
- assetProxy, // call address of asset proxy
- 0, // don't send any ETH
- cdStart, // pointer to start of input
- sub(cdEnd, cdStart), // length of input
- cdStart, // write output over input
- 512 // reserve 512 bytes for output
- )
- if iszero(success) {
- revert(cdStart, returndatasize())
- }
- }
- }
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol
deleted file mode 100644
index 736dcd0b1..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinExchangeCore.sol
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./libs/LibConstants.sol";
-import "./libs/LibFillResults.sol";
-import "./libs/LibOrder.sol";
-import "./libs/LibMath.sol";
-import "./mixins/MExchangeCore.sol";
-import "./mixins/MSignatureValidator.sol";
-import "./mixins/MTransactions.sol";
-import "./mixins/MAssetProxyDispatcher.sol";
-
-
-contract MixinExchangeCore is
- ReentrancyGuard,
- LibConstants,
- LibMath,
- LibOrder,
- LibFillResults,
- MAssetProxyDispatcher,
- MExchangeCore,
- MSignatureValidator,
- MTransactions
-{
- // Mapping of orderHash => amount of takerAsset already bought by maker
- mapping (bytes32 => uint256) public filled;
-
- // Mapping of orderHash => cancelled
- mapping (bytes32 => bool) public cancelled;
-
- // Mapping of makerAddress => senderAddress => lowest salt an order can have in order to be fillable
- // Orders with specified senderAddress and with a salt less than their epoch are considered cancelled
- mapping (address => mapping (address => uint256)) public orderEpoch;
-
- /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress).
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- function cancelOrdersUpTo(uint256 targetOrderEpoch)
- external
- nonReentrant
- {
- address makerAddress = getCurrentContextAddress();
- // If this function is called via `executeTransaction`, we only update the orderEpoch for the makerAddress/msg.sender combination.
- // This allows external filter contracts to add rules to how orders are cancelled via this function.
- address senderAddress = makerAddress == msg.sender ? address(0) : msg.sender;
-
- // orderEpoch is initialized to 0, so to cancelUpTo we need salt + 1
- uint256 newOrderEpoch = targetOrderEpoch + 1;
- uint256 oldOrderEpoch = orderEpoch[makerAddress][senderAddress];
-
- // Ensure orderEpoch is monotonically increasing
- require(
- newOrderEpoch > oldOrderEpoch,
- "INVALID_NEW_ORDER_EPOCH"
- );
-
- // Update orderEpoch
- orderEpoch[makerAddress][senderAddress] = newOrderEpoch;
- emit CancelUpTo(
- makerAddress,
- senderAddress,
- newOrderEpoch
- );
- }
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrder(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- nonReentrant
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillResults;
- }
-
- /// @dev After calling, the order can not be filled anymore.
- /// Throws if order is invalid or sender does not have permission to cancel.
- /// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
- function cancelOrder(Order memory order)
- public
- nonReentrant
- {
- cancelOrderInternal(order);
- }
-
- /// @dev Gets information about an order: status, hash, and amount filled.
- /// @param order Order to gather information on.
- /// @return OrderInfo Information about the order and its state.
- /// See LibOrder.OrderInfo for a complete description.
- function getOrderInfo(Order memory order)
- public
- view
- returns (OrderInfo memory orderInfo)
- {
- // Compute the order hash
- orderInfo.orderHash = getOrderHash(order);
-
- // Fetch filled amount
- orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash];
-
- // If order.makerAssetAmount is zero, we also reject the order.
- // While the Exchange contract handles them correctly, they create
- // edge cases in the supporting infrastructure because they have
- // an 'infinite' price when computed by a simple division.
- if (order.makerAssetAmount == 0) {
- orderInfo.orderStatus = uint8(OrderStatus.INVALID_MAKER_ASSET_AMOUNT);
- return orderInfo;
- }
-
- // If order.takerAssetAmount is zero, then the order will always
- // be considered filled because 0 == takerAssetAmount == orderTakerAssetFilledAmount
- // Instead of distinguishing between unfilled and filled zero taker
- // amount orders, we choose not to support them.
- if (order.takerAssetAmount == 0) {
- orderInfo.orderStatus = uint8(OrderStatus.INVALID_TAKER_ASSET_AMOUNT);
- return orderInfo;
- }
-
- // Validate order availability
- if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) {
- orderInfo.orderStatus = uint8(OrderStatus.FULLY_FILLED);
- return orderInfo;
- }
-
- // Validate order expiration
- // solhint-disable-next-line not-rely-on-time
- if (block.timestamp >= order.expirationTimeSeconds) {
- orderInfo.orderStatus = uint8(OrderStatus.EXPIRED);
- return orderInfo;
- }
-
- // Check if order has been cancelled
- if (cancelled[orderInfo.orderHash]) {
- orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
- return orderInfo;
- }
- if (orderEpoch[order.makerAddress][order.senderAddress] > order.salt) {
- orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
- return orderInfo;
- }
-
- // All other statuses are ruled out: order is Fillable
- orderInfo.orderStatus = uint8(OrderStatus.FILLABLE);
- return orderInfo;
- }
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderInternal(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- // Fetch order info
- OrderInfo memory orderInfo = getOrderInfo(order);
-
- // Fetch taker address
- address takerAddress = getCurrentContextAddress();
-
- // Assert that the order is fillable by taker
- assertFillableOrder(
- order,
- orderInfo,
- takerAddress,
- signature
- );
-
- // Get amount of takerAsset to fill
- uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
- uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
-
- // Validate context
- assertValidFill(
- order,
- orderInfo,
- takerAssetFillAmount,
- takerAssetFilledAmount,
- fillResults.makerAssetFilledAmount
- );
-
- // Compute proportional fill amounts
- fillResults = calculateFillResults(order, takerAssetFilledAmount);
-
- // Update exchange internal state
- updateFilledState(
- order,
- takerAddress,
- orderInfo.orderHash,
- orderInfo.orderTakerAssetFilledAmount,
- fillResults
- );
-
- // Settle order
- settleOrder(
- order,
- takerAddress,
- fillResults
- );
-
- return fillResults;
- }
-
- /// @dev After calling, the order can not be filled anymore.
- /// Throws if order is invalid or sender does not have permission to cancel.
- /// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
- function cancelOrderInternal(Order memory order)
- internal
- {
- // Fetch current order status
- OrderInfo memory orderInfo = getOrderInfo(order);
-
- // Validate context
- assertValidCancel(order, orderInfo);
-
- // Perform cancel
- updateCancelledState(order, orderInfo.orderHash);
- }
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- function updateFilledState(
- Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- FillResults memory fillResults
- )
- internal
- {
- // Update state
- filled[orderHash] = safeAdd(orderTakerAssetFilledAmount, fillResults.takerAssetFilledAmount);
-
- // Log order
- emit Fill(
- order.makerAddress,
- order.feeRecipientAddress,
- takerAddress,
- msg.sender,
- fillResults.makerAssetFilledAmount,
- fillResults.takerAssetFilledAmount,
- fillResults.makerFeePaid,
- fillResults.takerFeePaid,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
- }
-
- /// @dev Updates state with results of cancelling an order.
- /// State is only updated if the order is currently fillable.
- /// Otherwise, updating state would have no effect.
- /// @param order that was cancelled.
- /// @param orderHash Hash of order that was cancelled.
- function updateCancelledState(
- Order memory order,
- bytes32 orderHash
- )
- internal
- {
- // Perform cancel
- cancelled[orderHash] = true;
-
- // Log cancel
- emit Cancel(
- order.makerAddress,
- order.feeRecipientAddress,
- msg.sender,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
- }
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAddress Address of order taker.
- /// @param signature Proof that the orders was created by its maker.
- function assertFillableOrder(
- Order memory order,
- OrderInfo memory orderInfo,
- address takerAddress,
- bytes memory signature
- )
- internal
- view
- {
- // An order can only be filled if its status is FILLABLE.
- require(
- orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
- "ORDER_UNFILLABLE"
- );
-
- // Validate sender is allowed to fill this order
- if (order.senderAddress != address(0)) {
- require(
- order.senderAddress == msg.sender,
- "INVALID_SENDER"
- );
- }
-
- // Validate taker is allowed to fill this order
- if (order.takerAddress != address(0)) {
- require(
- order.takerAddress == takerAddress,
- "INVALID_TAKER"
- );
- }
-
- // Validate Maker signature (check only if first time seen)
- if (orderInfo.orderTakerAssetFilledAmount == 0) {
- require(
- isValidSignature(
- orderInfo.orderHash,
- order.makerAddress,
- signature
- ),
- "INVALID_ORDER_SIGNATURE"
- );
- }
- }
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAssetFillAmount Desired amount of order to fill by taker.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
- function assertValidFill(
- Order memory order,
- OrderInfo memory orderInfo,
- uint256 takerAssetFillAmount, // TODO: use FillResults
- uint256 takerAssetFilledAmount,
- uint256 makerAssetFilledAmount
- )
- internal
- view
- {
- // Revert if fill amount is invalid
- // TODO: reconsider necessity for v2.1
- require(
- takerAssetFillAmount != 0,
- "INVALID_TAKER_AMOUNT"
- );
-
- // Make sure taker does not pay more than desired amount
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- takerAssetFilledAmount <= takerAssetFillAmount,
- "TAKER_OVERPAY"
- );
-
- // Make sure order is not overfilled
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount) <= order.takerAssetAmount,
- "ORDER_OVERFILL"
- );
-
- // Make sure order is filled at acceptable price.
- // The order has an implied price from the makers perspective:
- // order price = order.makerAssetAmount / order.takerAssetAmount
- // i.e. the number of makerAsset maker is paying per takerAsset. The
- // maker is guaranteed to get this price or a better (lower) one. The
- // actual price maker is getting in this fill is:
- // fill price = makerAssetFilledAmount / takerAssetFilledAmount
- // We need `fill price <= order price` for the fill to be fair to maker.
- // This amounts to:
- // makerAssetFilledAmount order.makerAssetAmount
- // ------------------------ <= -----------------------
- // takerAssetFilledAmount order.takerAssetAmount
- // or, equivalently:
- // makerAssetFilledAmount * order.takerAssetAmount <=
- // order.makerAssetAmount * takerAssetFilledAmount
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- safeMul(makerAssetFilledAmount, order.takerAssetAmount)
- <=
- safeMul(order.makerAssetAmount, takerAssetFilledAmount),
- "INVALID_FILL_PRICE"
- );
- }
-
- /// @dev Validates context for cancelOrder. Succeeds or throws.
- /// @param order to be cancelled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- function assertValidCancel(
- Order memory order,
- OrderInfo memory orderInfo
- )
- internal
- view
- {
- // Ensure order is valid
- // An order can only be cancelled if its status is FILLABLE.
- require(
- orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
- "ORDER_UNFILLABLE"
- );
-
- // Validate sender is allowed to cancel this order
- if (order.senderAddress != address(0)) {
- require(
- order.senderAddress == msg.sender,
- "INVALID_SENDER"
- );
- }
-
- // Validate transaction signed by maker
- address makerAddress = getCurrentContextAddress();
- require(
- order.makerAddress == makerAddress,
- "INVALID_MAKER"
- );
- }
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function calculateFillResults(
- Order memory order,
- uint256 takerAssetFilledAmount
- )
- internal
- pure
- returns (FillResults memory fillResults)
- {
- // Compute proportional transfer amounts
- fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
- fillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
- takerAssetFilledAmount,
- order.takerAssetAmount,
- order.makerAssetAmount
- );
- fillResults.makerFeePaid = safeGetPartialAmountFloor(
- fillResults.makerAssetFilledAmount,
- order.makerAssetAmount,
- order.makerFee
- );
- fillResults.takerFeePaid = safeGetPartialAmountFloor(
- takerAssetFilledAmount,
- order.takerAssetAmount,
- order.takerFee
- );
-
- return fillResults;
- }
-
- /// @dev Settles an order by transferring assets between counterparties.
- /// @param order Order struct containing order specifications.
- /// @param takerAddress Address selling takerAsset and buying makerAsset.
- /// @param fillResults Amounts to be filled and fees paid by maker and taker.
- function settleOrder(
- LibOrder.Order memory order,
- address takerAddress,
- LibFillResults.FillResults memory fillResults
- )
- private
- {
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- dispatchTransferFrom(
- order.makerAssetData,
- order.makerAddress,
- takerAddress,
- fillResults.makerAssetFilledAmount
- );
- dispatchTransferFrom(
- order.takerAssetData,
- takerAddress,
- order.makerAddress,
- fillResults.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- zrxAssetData,
- order.makerAddress,
- order.feeRecipientAddress,
- fillResults.makerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- order.feeRecipientAddress,
- fillResults.takerFeePaid
- );
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol
deleted file mode 100644
index b4f6bdb26..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinMatchOrders.sol
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./libs/LibConstants.sol";
-import "./libs/LibMath.sol";
-import "./libs/LibOrder.sol";
-import "./libs/LibFillResults.sol";
-import "./mixins/MExchangeCore.sol";
-import "./mixins/MMatchOrders.sol";
-import "./mixins/MTransactions.sol";
-import "./mixins/MAssetProxyDispatcher.sol";
-
-
-contract MixinMatchOrders is
- ReentrancyGuard,
- LibConstants,
- LibMath,
- MAssetProxyDispatcher,
- MExchangeCore,
- MMatchOrders,
- MTransactions
-{
- /// @dev Match two complementary orders that have a profitable spread.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the left order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftSignature Proof that order was created by the left maker.
- /// @param rightSignature Proof that order was created by the right maker.
- /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- bytes memory leftSignature,
- bytes memory rightSignature
- )
- public
- nonReentrant
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
- // If this assumption isn't true, the match will fail at signature validation.
- rightOrder.makerAssetData = leftOrder.takerAssetData;
- rightOrder.takerAssetData = leftOrder.makerAssetData;
-
- // Get left & right order info
- LibOrder.OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
- LibOrder.OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
-
- // Fetch taker address
- address takerAddress = getCurrentContextAddress();
-
- // Either our context is valid or we revert
- assertFillableOrder(
- leftOrder,
- leftOrderInfo,
- takerAddress,
- leftSignature
- );
- assertFillableOrder(
- rightOrder,
- rightOrderInfo,
- takerAddress,
- rightSignature
- );
- assertValidMatch(leftOrder, rightOrder);
-
- // Compute proportional fill amounts
- matchedFillResults = calculateMatchedFillResults(
- leftOrder,
- rightOrder,
- leftOrderInfo.orderTakerAssetFilledAmount,
- rightOrderInfo.orderTakerAssetFilledAmount
- );
-
- // Validate fill contexts
- assertValidFill(
- leftOrder,
- leftOrderInfo,
- matchedFillResults.left.takerAssetFilledAmount,
- matchedFillResults.left.takerAssetFilledAmount,
- matchedFillResults.left.makerAssetFilledAmount
- );
- assertValidFill(
- rightOrder,
- rightOrderInfo,
- matchedFillResults.right.takerAssetFilledAmount,
- matchedFillResults.right.takerAssetFilledAmount,
- matchedFillResults.right.makerAssetFilledAmount
- );
-
- // Update exchange state
- updateFilledState(
- leftOrder,
- takerAddress,
- leftOrderInfo.orderHash,
- leftOrderInfo.orderTakerAssetFilledAmount,
- matchedFillResults.left
- );
- updateFilledState(
- rightOrder,
- takerAddress,
- rightOrderInfo.orderHash,
- rightOrderInfo.orderTakerAssetFilledAmount,
- matchedFillResults.right
- );
-
- // Settle matched orders. Succeeds or throws.
- settleMatchedOrders(
- leftOrder,
- rightOrder,
- takerAddress,
- matchedFillResults
- );
-
- return matchedFillResults;
- }
-
- /// @dev Validates context for matchOrders. Succeeds or throws.
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- function assertValidMatch(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder
- )
- internal
- pure
- {
- // Make sure there is a profitable spread.
- // There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
- // than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
- // This is satisfied by the equations below:
- // <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
- // AND
- // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
- // These equations can be combined to get the following:
- require(
- safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
- safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
- "NEGATIVE_SPREAD_REQUIRED"
- );
- }
-
- /// @dev Calculates fill amounts for the matched orders.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the leftOrder order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
- /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
- /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
- function calculateMatchedFillResults(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- uint256 leftOrderTakerAssetFilledAmount,
- uint256 rightOrderTakerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- // Derive maker asset amounts for left & right orders, given store taker assert amounts
- uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
- uint256 leftMakerAssetAmountRemaining = safeGetPartialAmountFloor(
- leftOrder.makerAssetAmount,
- leftOrder.takerAssetAmount,
- leftTakerAssetAmountRemaining
- );
- uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
- uint256 rightMakerAssetAmountRemaining = safeGetPartialAmountFloor(
- rightOrder.makerAssetAmount,
- rightOrder.takerAssetAmount,
- rightTakerAssetAmountRemaining
- );
-
- // Calculate fill results for maker and taker assets: at least one order will be fully filled.
- // The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining`
- // The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining`
- // We have two distinct cases for calculating the fill results:
- // Case 1.
- // If the left maker can buy more than the right maker can sell, then only the right order is fully filled.
- // If the left maker can buy exactly what the right maker can sell, then both orders are fully filled.
- // Case 2.
- // If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled.
- if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) {
- // Case 1: Right order is fully filled
- matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining;
- matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining;
- matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount;
- // Round down to ensure the maker's exchange rate does not exceed the price specified by the order.
- // We favor the maker when the exchange rate must be rounded.
- matchedFillResults.left.makerAssetFilledAmount = safeGetPartialAmountFloor(
- leftOrder.makerAssetAmount,
- leftOrder.takerAssetAmount,
- matchedFillResults.left.takerAssetFilledAmount
- );
- } else {
- // Case 2: Left order is fully filled
- matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining;
- matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining;
- matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount;
- // Round up to ensure the maker's exchange rate does not exceed the price specified by the order.
- // We favor the maker when the exchange rate must be rounded.
- matchedFillResults.right.takerAssetFilledAmount = safeGetPartialAmountCeil(
- rightOrder.takerAssetAmount,
- rightOrder.makerAssetAmount,
- matchedFillResults.right.makerAssetFilledAmount
- );
- }
-
- // Calculate amount given to taker
- matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
- matchedFillResults.left.makerAssetFilledAmount,
- matchedFillResults.right.takerAssetFilledAmount
- );
-
- // Compute fees for left order
- matchedFillResults.left.makerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.left.makerAssetFilledAmount,
- leftOrder.makerAssetAmount,
- leftOrder.makerFee
- );
- matchedFillResults.left.takerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.left.takerAssetFilledAmount,
- leftOrder.takerAssetAmount,
- leftOrder.takerFee
- );
-
- // Compute fees for right order
- matchedFillResults.right.makerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.right.makerAssetFilledAmount,
- rightOrder.makerAssetAmount,
- rightOrder.makerFee
- );
- matchedFillResults.right.takerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.right.takerAssetFilledAmount,
- rightOrder.takerAssetAmount,
- rightOrder.takerFee
- );
-
- // Return fill results
- return matchedFillResults;
- }
-
- /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
- /// @param leftOrder First matched order.
- /// @param rightOrder Second matched order.
- /// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
- /// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
- function settleMatchedOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- address takerAddress,
- LibFillResults.MatchedFillResults memory matchedFillResults
- )
- private
- {
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- // Order makers and taker
- dispatchTransferFrom(
- leftOrder.makerAssetData,
- leftOrder.makerAddress,
- rightOrder.makerAddress,
- matchedFillResults.right.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- rightOrder.makerAssetData,
- rightOrder.makerAddress,
- leftOrder.makerAddress,
- matchedFillResults.left.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- leftOrder.makerAssetData,
- leftOrder.makerAddress,
- takerAddress,
- matchedFillResults.leftMakerAssetSpreadAmount
- );
-
- // Maker fees
- dispatchTransferFrom(
- zrxAssetData,
- leftOrder.makerAddress,
- leftOrder.feeRecipientAddress,
- matchedFillResults.left.makerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- rightOrder.makerAddress,
- rightOrder.feeRecipientAddress,
- matchedFillResults.right.makerFeePaid
- );
-
- // Taker fees
- if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- leftOrder.feeRecipientAddress,
- safeAdd(
- matchedFillResults.left.takerFeePaid,
- matchedFillResults.right.takerFeePaid
- )
- );
- } else {
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- leftOrder.feeRecipientAddress,
- matchedFillResults.left.takerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- rightOrder.feeRecipientAddress,
- matchedFillResults.right.takerFeePaid
- );
- }
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol
deleted file mode 100644
index 176e28351..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinSignatureValidator.sol
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
-
- 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/LibBytes/LibBytes.sol";
-import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./mixins/MSignatureValidator.sol";
-import "./mixins/MTransactions.sol";
-import "./interfaces/IWallet.sol";
-import "./interfaces/IValidator.sol";
-
-
-contract MixinSignatureValidator is
- ReentrancyGuard,
- MSignatureValidator,
- MTransactions
-{
- using LibBytes for bytes;
-
- // Mapping of hash => signer => signed
- mapping (bytes32 => mapping (address => bool)) public preSigned;
-
- // Mapping of signer => validator => approved
- mapping (address => mapping (address => bool)) public allowedValidators;
-
- /// @dev Approves a hash on-chain using any valid signature type.
- /// After presigning a hash, the preSign signature type will become valid for that hash and signer.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- function preSign(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- {
- if (signerAddress != msg.sender) {
- require(
- isValidSignature(
- hash,
- signerAddress,
- signature
- ),
- "INVALID_SIGNATURE"
- );
- }
- preSigned[hash][signerAddress] = true;
- }
-
- /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
- /// @param validatorAddress Address of Validator contract.
- /// @param approval Approval or disapproval of Validator contract.
- function setSignatureValidatorApproval(
- address validatorAddress,
- bool approval
- )
- external
- nonReentrant
- {
- address signerAddress = getCurrentContextAddress();
- allowedValidators[signerAddress][validatorAddress] = approval;
- emit SignatureValidatorApproval(
- signerAddress,
- validatorAddress,
- approval
- );
- }
-
- /// @dev Verifies that a hash has been signed by the given signer.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes memory signature
- )
- public
- view
- returns (bool isValid)
- {
- require(
- signature.length > 0,
- "LENGTH_GREATER_THAN_0_REQUIRED"
- );
-
- // Pop last byte off of signature byte array.
- uint8 signatureTypeRaw = uint8(signature.popLastByte());
-
- // Ensure signature is supported
- require(
- signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
- "SIGNATURE_UNSUPPORTED"
- );
-
- SignatureType signatureType = SignatureType(signatureTypeRaw);
-
- // Variables are not scoped in Solidity.
- uint8 v;
- bytes32 r;
- bytes32 s;
- address recovered;
-
- // Always illegal signature.
- // This is always an implicit option since a signer can create a
- // signature array with invalid type or length. We may as well make
- // it an explicit option. This aids testing and analysis. It is
- // also the initialization value for the enum type.
- if (signatureType == SignatureType.Illegal) {
- revert("SIGNATURE_ILLEGAL");
-
- // Always invalid signature.
- // Like Illegal, this is always implicitly available and therefore
- // offered explicitly. It can be implicitly created by providing
- // a correctly formatted but incorrect signature.
- } else if (signatureType == SignatureType.Invalid) {
- require(
- signature.length == 0,
- "LENGTH_0_REQUIRED"
- );
- isValid = false;
- return isValid;
-
- // Signature using EIP712
- } else if (signatureType == SignatureType.EIP712) {
- require(
- signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
- v = uint8(signature[0]);
- r = signature.readBytes32(1);
- s = signature.readBytes32(33);
- recovered = ecrecover(
- hash,
- v,
- r,
- s
- );
- isValid = signerAddress == recovered;
- return isValid;
-
- // Signed using web3.eth_sign
- } else if (signatureType == SignatureType.EthSign) {
- require(
- signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
- v = uint8(signature[0]);
- r = signature.readBytes32(1);
- s = signature.readBytes32(33);
- recovered = ecrecover(
- keccak256(abi.encodePacked(
- "\x19Ethereum Signed Message:\n32",
- hash
- )),
- v,
- r,
- s
- );
- isValid = signerAddress == recovered;
- return isValid;
-
- // Signature verified by wallet contract.
- // If used with an order, the maker of the order is the wallet contract.
- } else if (signatureType == SignatureType.Wallet) {
- isValid = isValidWalletSignature(
- hash,
- signerAddress,
- signature
- );
- return isValid;
-
- // Signature verified by validator contract.
- // If used with an order, the maker of the order can still be an EOA.
- // A signature using this type should be encoded as:
- // | Offset | Length | Contents |
- // | 0x00 | x | Signature to validate |
- // | 0x00 + x | 20 | Address of validator contract |
- // | 0x14 + x | 1 | Signature type is always "\x06" |
- } else if (signatureType == SignatureType.Validator) {
- // Pop last 20 bytes off of signature byte array.
- address validatorAddress = signature.popLast20Bytes();
-
- // Ensure signer has approved validator.
- if (!allowedValidators[signerAddress][validatorAddress]) {
- return false;
- }
- isValid = isValidValidatorSignature(
- validatorAddress,
- hash,
- signerAddress,
- signature
- );
- return isValid;
-
- // Signer signed hash previously using the preSign function.
- } else if (signatureType == SignatureType.PreSigned) {
- isValid = preSigned[hash][signerAddress];
- return isValid;
- }
-
- // Anything else is illegal (We do not return false because
- // the signature may actually be valid, just not in a format
- // that we currently support. In this case returning false
- // may lead the caller to incorrectly believe that the
- // signature was invalid.)
- revert("SIGNATURE_UNSUPPORTED");
- }
-
- /// @dev Verifies signature using logic defined by Wallet contract.
- /// @param hash Any 32 byte hash.
- /// @param walletAddress Address that should have signed the given hash
- /// and defines its own signature verification method.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if signature is valid for given wallet..
- function isValidWalletSignature(
- bytes32 hash,
- address walletAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid)
- {
- bytes memory calldata = abi.encodeWithSelector(
- IWallet(walletAddress).isValidSignature.selector,
- hash,
- signature
- );
- assembly {
- let cdStart := add(calldata, 32)
- let success := staticcall(
- gas, // forward all gas
- walletAddress, // address of Wallet contract
- cdStart, // pointer to start of input
- mload(calldata), // length of input
- cdStart, // write output over input
- 32 // output size is 32 bytes
- )
-
- switch success
- case 0 {
- // Revert with `Error("WALLET_ERROR")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
- case 1 {
- // Signature is valid if call did not revert and returned true
- isValid := mload(cdStart)
- }
- }
- return isValid;
- }
-
- /// @dev Verifies signature using logic defined by Validator contract.
- /// @param validatorAddress Address of validator contract.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidValidatorSignature(
- address validatorAddress,
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid)
- {
- bytes memory calldata = abi.encodeWithSelector(
- IValidator(signerAddress).isValidSignature.selector,
- hash,
- signerAddress,
- signature
- );
- assembly {
- let cdStart := add(calldata, 32)
- let success := staticcall(
- gas, // forward all gas
- validatorAddress, // address of Validator contract
- cdStart, // pointer to start of input
- mload(calldata), // length of input
- cdStart, // write output over input
- 32 // output size is 32 bytes
- )
-
- switch success
- case 0 {
- // Revert with `Error("VALIDATOR_ERROR")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f56414c494441544f525f4552524f5200000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
- case 1 {
- // Signature is valid if call did not revert and returned true
- isValid := mload(cdStart)
- }
- }
- return isValid;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol b/packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol
deleted file mode 100644
index 3a76ca202..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinTransactions.sol
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-
- 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 "./libs/LibExchangeErrors.sol";
-import "./mixins/MSignatureValidator.sol";
-import "./mixins/MTransactions.sol";
-import "./libs/LibEIP712.sol";
-
-
-contract MixinTransactions is
- LibEIP712,
- MSignatureValidator,
- MTransactions
-{
- // Mapping of transaction hash => executed
- // This prevents transactions from being executed more than once.
- mapping (bytes32 => bool) public transactions;
-
- // Address of current transaction signer
- address public currentContextAddress;
-
- /// @dev Executes an exchange method call in the context of signer.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes data,
- bytes signature
- )
- external
- {
- // Prevent reentrancy
- require(
- currentContextAddress == address(0),
- "REENTRANCY_ILLEGAL"
- );
-
- bytes32 transactionHash = hashEIP712Message(hashZeroExTransaction(
- salt,
- signerAddress,
- data
- ));
-
- // Validate transaction has not been executed
- require(
- !transactions[transactionHash],
- "INVALID_TX_HASH"
- );
-
- // Transaction always valid if signer is sender of transaction
- if (signerAddress != msg.sender) {
- // Validate signature
- require(
- isValidSignature(
- transactionHash,
- signerAddress,
- signature
- ),
- "INVALID_TX_SIGNATURE"
- );
-
- // Set the current transaction signer
- currentContextAddress = signerAddress;
- }
-
- // Execute transaction
- transactions[transactionHash] = true;
- require(
- address(this).delegatecall(data),
- "FAILED_EXECUTION"
- );
-
- // Reset current transaction signer if it was previously updated
- if (signerAddress != msg.sender) {
- currentContextAddress = address(0);
- }
- }
-
- /// @dev Calculates EIP712 hash of the Transaction.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @return EIP712 hash of the Transaction.
- function hashZeroExTransaction(
- uint256 salt,
- address signerAddress,
- bytes memory data
- )
- internal
- pure
- returns (bytes32 result)
- {
- bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
- bytes32 dataHash = keccak256(data);
-
- // Assembly for more efficiently computing:
- // keccak256(abi.encodePacked(
- // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
- // salt,
- // bytes32(signerAddress),
- // keccak256(data)
- // ));
-
- assembly {
- // Load free memory pointer
- let memPtr := mload(64)
-
- mstore(memPtr, schemaHash) // hash of schema
- mstore(add(memPtr, 32), salt) // salt
- mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress
- mstore(add(memPtr, 96), dataHash) // hash of data
-
- // Compute hash
- result := keccak256(memPtr, 128)
- }
- return result;
- }
-
- /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
- /// If calling a fill function, this address will represent the taker.
- /// If calling a cancel function, this address will represent the maker.
- /// @return Signer of 0x transaction if entry point is `executeTransaction`.
- /// `msg.sender` if entry point is any other function.
- function getCurrentContextAddress()
- internal
- view
- returns (address)
- {
- address currentContextAddress_ = currentContextAddress;
- address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_;
- return contextAddress;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol
deleted file mode 100644
index cddff0e5f..000000000
--- a/packages/contracts/contracts/protocol/Exchange/MixinWrapperFunctions.sol
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../utils/ReentrancyGuard/ReentrancyGuard.sol";
-import "./libs/LibMath.sol";
-import "./libs/LibOrder.sol";
-import "./libs/LibFillResults.sol";
-import "./libs/LibAbiEncoder.sol";
-import "./mixins/MExchangeCore.sol";
-import "./mixins/MWrapperFunctions.sol";
-
-
-contract MixinWrapperFunctions is
- ReentrancyGuard,
- LibMath,
- LibFillResults,
- LibAbiEncoder,
- MExchangeCore,
- MWrapperFunctions
-{
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- nonReentrant
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrKillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillResults;
- }
-
- /// @dev Fills the input order.
- /// Returns false if the transaction would otherwise revert.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (FillResults memory fillResults)
- {
- // ABI encode calldata for `fillOrder`
- bytes memory fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
-
- // Delegate to `fillOrder` and handle any exceptions gracefully
- assembly {
- let success := delegatecall(
- gas, // forward all gas
- address, // call address of this contract
- add(fillOrderCalldata, 32), // pointer to start of input (skip array length in first 32 bytes)
- mload(fillOrderCalldata), // length of input
- fillOrderCalldata, // write output over input
- 128 // output size is 128 bytes
- )
- if success {
- mstore(fillResults, mload(fillOrderCalldata))
- mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32)))
- mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64)))
- mstore(add(fillResults, 96), mload(add(fillOrderCalldata, 96)))
- }
- }
- // fillResults values will be 0 by default if call was unsuccessful
- return fillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrKill.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrKillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrKillOrderInternal(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrders(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- bytes memory takerAssetData = orders[0].takerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being sold by taker is the same for each order.
- // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
- orders[i].takerAssetData = takerAssetData;
-
- // Calculate the remaining amount of takerAsset to sell
- uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- bytes memory takerAssetData = orders[0].takerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being sold by taker is the same for each order.
- // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
- orders[i].takerAssetData = takerAssetData;
-
- // Calculate the remaining amount of takerAsset to sell
- uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrders(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
- orders[i].makerAssetData = makerAssetData;
-
- // Calculate the remaining amount of makerAsset to buy
- uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
-
- // Convert the remaining amount of makerAsset to buy into remaining amount
- // of takerAsset to sell, assuming entire amount can be sold in the current order
- uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of makerAsset has been bought
- if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
- orders[i].makerAssetData = makerAssetData;
-
- // Calculate the remaining amount of makerAsset to buy
- uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
-
- // Convert the remaining amount of makerAsset to buy into remaining amount
- // of takerAsset to sell, assuming entire amount can be sold in the current order
- uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of makerAsset has been bought
- if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously cancels multiple orders in a single transaction.
- /// @param orders Array of order specifications.
- function batchCancelOrders(LibOrder.Order[] memory orders)
- public
- nonReentrant
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- cancelOrderInternal(orders[i]);
- }
- }
-
- /// @dev Fetches information for all passed in orders.
- /// @param orders Array of order specifications.
- /// @return Array of OrderInfo instances that correspond to each order.
- function getOrdersInfo(LibOrder.Order[] memory orders)
- public
- view
- returns (LibOrder.OrderInfo[] memory)
- {
- uint256 ordersLength = orders.length;
- LibOrder.OrderInfo[] memory ordersInfo = new LibOrder.OrderInfo[](ordersLength);
- for (uint256 i = 0; i != ordersLength; i++) {
- ordersInfo[i] = getOrderInfo(orders[i]);
- }
- return ordersInfo;
- }
-
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- require(
- fillResults.takerAssetFilledAmount == takerAssetFillAmount,
- "COMPLETE_FILL_FAILED"
- );
- return fillResults;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
deleted file mode 100644
index 8db8d6f6c..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
- 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;
-
-
-contract IAssetProxyDispatcher {
-
- /// @dev Registers an asset proxy to its asset proxy id.
- /// Once an asset proxy is registered, it cannot be unregistered.
- /// @param assetProxy Address of new asset proxy to register.
- function registerAssetProxy(address assetProxy)
- external;
-
- /// @dev Gets an asset proxy.
- /// @param assetProxyId Id of the asset proxy.
- /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
- function getAssetProxy(bytes4 assetProxyId)
- external
- view
- returns (address);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol
deleted file mode 100644
index b92abba04..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchange.sol
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./IExchangeCore.sol";
-import "./IMatchOrders.sol";
-import "./ISignatureValidator.sol";
-import "./ITransactions.sol";
-import "./IAssetProxyDispatcher.sol";
-import "./IWrapperFunctions.sol";
-
-
-// solhint-disable no-empty-blocks
-contract IExchange is
- IExchangeCore,
- IMatchOrders,
- ISignatureValidator,
- ITransactions,
- IAssetProxyDispatcher,
- IWrapperFunctions
-{}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol
deleted file mode 100644
index 9995e0385..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IExchangeCore.sol
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-
-
-contract IExchangeCore {
-
- /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress).
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- function cancelOrdersUpTo(uint256 targetOrderEpoch)
- external;
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev After calling, the order can not be filled anymore.
- /// @param order Order struct containing order specifications.
- function cancelOrder(LibOrder.Order memory order)
- public;
-
- /// @dev Gets information about an order: status, hash, and amount filled.
- /// @param order Order to gather information on.
- /// @return OrderInfo Information about the order and its state.
- /// See LibOrder.OrderInfo for a complete description.
- function getOrderInfo(LibOrder.Order memory order)
- public
- view
- returns (LibOrder.OrderInfo memory orderInfo);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol
deleted file mode 100644
index 73447f3ae..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IMatchOrders.sol
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-
-
-contract IMatchOrders {
-
- /// @dev Match two complementary orders that have a profitable spread.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the left order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftSignature Proof that order was created by the left maker.
- /// @param rightSignature Proof that order was created by the right maker.
- /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- bytes memory leftSignature,
- bytes memory rightSignature
- )
- public
- returns (LibFillResults.MatchedFillResults memory matchedFillResults);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol
deleted file mode 100644
index 1fd0eccf0..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/ISignatureValidator.sol
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-
- 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;
-
-
-contract ISignatureValidator {
-
- /// @dev Approves a hash on-chain using any valid signature type.
- /// After presigning a hash, the preSign signature type will become valid for that hash and signer.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- function preSign(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external;
-
- /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
- /// @param validatorAddress Address of Validator contract.
- /// @param approval Approval or disapproval of Validator contract.
- function setSignatureValidatorApproval(
- address validatorAddress,
- bool approval
- )
- external;
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address of signer.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes memory signature
- )
- public
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol
deleted file mode 100644
index 4446c55ce..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/ITransactions.sol
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-
- 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;
-
-
-contract ITransactions {
-
- /// @dev Executes an exchange method call in the context of signer.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes data,
- bytes signature
- )
- external;
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol
deleted file mode 100644
index 2dd69100c..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IValidator.sol
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
- 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;
-
-
-contract IValidator {
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol
deleted file mode 100644
index c97161ca6..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IWallet.sol
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-
- 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;
-
-
-contract IWallet {
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- bytes signature
- )
- external
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol b/packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol
deleted file mode 100644
index 56a533646..000000000
--- a/packages/contracts/contracts/protocol/Exchange/interfaces/IWrapperFunctions.sol
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-
-
-contract IWrapperFunctions {
-
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrKill.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrKillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrders(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrders(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously cancels multiple orders in a single transaction.
- /// @param orders Array of order specifications.
- function batchCancelOrders(LibOrder.Order[] memory orders)
- public;
-
- /// @dev Fetches information for all passed in orders
- /// @param orders Array of order specifications.
- /// @return Array of OrderInfo instances that correspond to each order.
- function getOrdersInfo(LibOrder.Order[] memory orders)
- public
- view
- returns (LibOrder.OrderInfo[] memory);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol
deleted file mode 100644
index 4aad37709..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibAbiEncoder.sol
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "./LibOrder.sol";
-
-
-contract LibAbiEncoder {
-
- /// @dev ABI encodes calldata for `fillOrder`.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return ABI encoded calldata for `fillOrder`.
- function abiEncodeFillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- pure
- returns (bytes memory fillOrderCalldata)
- {
- // We need to call MExchangeCore.fillOrder using a delegatecall in
- // assembly so that we can intercept a call that throws. For this, we
- // need the input encoded in memory in the Ethereum ABIv2 format [1].
-
- // | Area | Offset | Length | Contents |
- // | -------- |--------|---------|-------------------------------------------- |
- // | Header | 0x00 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 0x00 | | 1. offset to order (*) |
- // | | 0x20 | | 2. takerAssetFillAmount |
- // | | 0x40 | | 3. offset to signature (*) |
- // | Data | | 12 * 32 | order: |
- // | | 0x000 | | 1. senderAddress |
- // | | 0x020 | | 2. makerAddress |
- // | | 0x040 | | 3. takerAddress |
- // | | 0x060 | | 4. feeRecipientAddress |
- // | | 0x080 | | 5. makerAssetAmount |
- // | | 0x0A0 | | 6. takerAssetAmount |
- // | | 0x0C0 | | 7. makerFeeAmount |
- // | | 0x0E0 | | 8. takerFeeAmount |
- // | | 0x100 | | 9. expirationTimeSeconds |
- // | | 0x120 | | 10. salt |
- // | | 0x140 | | 11. Offset to makerAssetData (*) |
- // | | 0x160 | | 12. Offset to takerAssetData (*) |
- // | | 0x180 | 32 | makerAssetData Length |
- // | | 0x1A0 | ** | makerAssetData Contents |
- // | | 0x1C0 | 32 | takerAssetData Length |
- // | | 0x1E0 | ** | takerAssetData Contents |
- // | | 0x200 | 32 | signature Length |
- // | | 0x220 | ** | signature Contents |
-
- // * Offsets are calculated from the beginning of the current area: Header, Params, Data:
- // An offset stored in the Params area is calculated from the beginning of the Params section.
- // An offset stored in the Data area is calculated from the beginning of the Data section.
-
- // ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
-
- // [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
-
- assembly {
-
- // Areas below may use the following variables:
- // 1. <area>Start -- Start of this area in memory
- // 2. <area>End -- End of this area in memory. This value may
- // be precomputed (before writing contents),
- // or it may be computed as contents are written.
- // 3. <area>Offset -- Current offset into area. If an area's End
- // is precomputed, this variable tracks the
- // offsets of contents as they are written.
-
- /////// Setup Header Area ///////
- // Load free memory pointer
- fillOrderCalldata := mload(0x40)
- // bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"))
- // = 0xb4be83d5
- // Leave 0x20 bytes to store the length
- mstore(add(fillOrderCalldata, 0x20), 0xb4be83d500000000000000000000000000000000000000000000000000000000)
- let headerAreaEnd := add(fillOrderCalldata, 0x24)
-
- /////// Setup Params Area ///////
- // This area is preallocated and written to later.
- // This is because we need to fill in offsets that have not yet been calculated.
- let paramsAreaStart := headerAreaEnd
- let paramsAreaEnd := add(paramsAreaStart, 0x60)
- let paramsAreaOffset := paramsAreaStart
-
- /////// Setup Data Area ///////
- let dataAreaStart := paramsAreaEnd
- let dataAreaEnd := dataAreaStart
-
- // Offset from the source data we're reading from
- let sourceOffset := order
- // arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
- let arrayLenBytes := 0
- let arrayLenWords := 0
-
- /////// Write order Struct ///////
- // Write memory location of Order, relative to the start of the
- // parameter list, then increment the paramsAreaOffset respectively.
- mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
- paramsAreaOffset := add(paramsAreaOffset, 0x20)
-
- // Write values for each field in the order
- // It would be nice to use a loop, but we save on gas by writing
- // the stores sequentially.
- mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
- mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
- mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
- mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
- mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
- mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
- mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
- mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
- mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
- mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
- mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
- mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
- dataAreaEnd := add(dataAreaEnd, 0x180)
- sourceOffset := add(sourceOffset, 0x180)
-
- // Write offset to <order.makerAssetData>
- mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
-
- // Calculate length of <order.makerAssetData>
- sourceOffset := mload(add(order, 0x140)) // makerAssetData
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of <order.makerAssetData>
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of <order.makerAssetData>
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- // Write offset to <order.takerAssetData>
- mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
-
- // Calculate length of <order.takerAssetData>
- sourceOffset := mload(add(order, 0x160)) // takerAssetData
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of <order.takerAssetData>
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of <order.takerAssetData>
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- /////// Write takerAssetFillAmount ///////
- mstore(paramsAreaOffset, takerAssetFillAmount)
- paramsAreaOffset := add(paramsAreaOffset, 0x20)
-
- /////// Write signature ///////
- // Write offset to paramsArea
- mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
-
- // Calculate length of signature
- sourceOffset := signature
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of signature
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of signature
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- // Set length of calldata
- mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20)))
-
- // Increment free memory pointer
- mstore(0x40, dataAreaEnd)
- }
-
- return fillOrderCalldata;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol
deleted file mode 100644
index 8d2732cd3..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibConstants.sol
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-
- 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;
-
-
-// solhint-disable max-line-length
-contract LibConstants {
-
- // Asset data for ZRX token. Used for fee transfers.
- // @TODO: Hardcode constant when we deploy. Currently
- // not constant to make testing easier.
-
- // The proxyId for ZRX_ASSET_DATA is bytes4(keccak256("ERC20Token(address)")) = 0xf47261b0
-
- // Kovan ZRX address is 0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570.
- // The ABI encoded proxyId and address is 0xf47261b00000000000000000000000006ff6c0ff1d68b964901f986d4c9fa3ac68346570
- // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70";
-
- // Mainnet ZRX address is 0xe41d2489571d322189246dafa5ebde1f4699f498.
- // The ABI encoded proxyId and address is 0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498
- // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98";
-
- // solhint-disable-next-line var-name-mixedcase
- bytes public ZRX_ASSET_DATA;
-
- // @TODO: Remove when we deploy.
- constructor (bytes memory zrxAssetData)
- public
- {
- ZRX_ASSET_DATA = zrxAssetData;
- }
-}
-// solhint-enable max-line-length
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol
deleted file mode 100644
index 203edc1fd..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibEIP712.sol
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
- 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;
-
-
-contract LibEIP712 {
-
- // EIP191 header for EIP712 prefix
- string constant internal EIP191_HEADER = "\x19\x01";
-
- // EIP712 Domain Name value
- string constant internal EIP712_DOMAIN_NAME = "0x Protocol";
-
- // EIP712 Domain Version value
- string constant internal EIP712_DOMAIN_VERSION = "2";
-
- // Hash of the EIP712 Domain Separator Schema
- bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
- "EIP712Domain(",
- "string name,",
- "string version,",
- "address verifyingContract",
- ")"
- ));
-
- // Hash of the EIP712 Domain Separator data
- // solhint-disable-next-line var-name-mixedcase
- bytes32 public EIP712_DOMAIN_HASH;
-
- constructor ()
- public
- {
- EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(
- EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
- keccak256(bytes(EIP712_DOMAIN_NAME)),
- keccak256(bytes(EIP712_DOMAIN_VERSION)),
- bytes32(address(this))
- ));
- }
-
- /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.
- /// @param hashStruct The EIP712 hash struct.
- /// @return EIP712 hash applied to this EIP712 Domain.
- function hashEIP712Message(bytes32 hashStruct)
- internal
- view
- returns (bytes32 result)
- {
- bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;
-
- // Assembly for more efficient computing:
- // keccak256(abi.encodePacked(
- // EIP191_HEADER,
- // EIP712_DOMAIN_HASH,
- // hashStruct
- // ));
-
- assembly {
- // Load free memory pointer
- let memPtr := mload(64)
-
- mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
- mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
- mstore(add(memPtr, 34), hashStruct) // Hash of struct
-
- // Compute hash
- result := keccak256(memPtr, 66)
- }
- return result;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol
deleted file mode 100644
index a0f75bc06..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibExchangeErrors.sol
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-
- 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.
-
-*/
-
-// solhint-disable
-pragma solidity 0.4.24;
-
-
-/// @dev This contract documents the revert reasons used in the Exchange contract.
-/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
-contract LibExchangeErrors {
-
- /// Order validation errors ///
- string constant ORDER_UNFILLABLE = "ORDER_UNFILLABLE"; // Order cannot be filled.
- string constant INVALID_MAKER = "INVALID_MAKER"; // Invalid makerAddress.
- string constant INVALID_TAKER = "INVALID_TAKER"; // Invalid takerAddress.
- string constant INVALID_SENDER = "INVALID_SENDER"; // Invalid `msg.sender`.
- string constant INVALID_ORDER_SIGNATURE = "INVALID_ORDER_SIGNATURE"; // Signature validation failed.
-
- /// fillOrder validation errors ///
- string constant INVALID_TAKER_AMOUNT = "INVALID_TAKER_AMOUNT"; // takerAssetFillAmount cannot equal 0.
- string constant ROUNDING_ERROR = "ROUNDING_ERROR"; // Rounding error greater than 0.1% of takerAssetFillAmount.
-
- /// Signature validation errors ///
- string constant INVALID_SIGNATURE = "INVALID_SIGNATURE"; // Signature validation failed.
- string constant SIGNATURE_ILLEGAL = "SIGNATURE_ILLEGAL"; // Signature type is illegal.
- string constant SIGNATURE_UNSUPPORTED = "SIGNATURE_UNSUPPORTED"; // Signature type unsupported.
-
- /// cancelOrdersUptTo errors ///
- string constant INVALID_NEW_ORDER_EPOCH = "INVALID_NEW_ORDER_EPOCH"; // Specified salt must be greater than or equal to existing orderEpoch.
-
- /// fillOrKillOrder errors ///
- string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired takerAssetFillAmount could not be completely filled.
-
- /// matchOrders errors ///
- string constant NEGATIVE_SPREAD_REQUIRED = "NEGATIVE_SPREAD_REQUIRED"; // Matched orders must have a negative spread.
-
- /// Transaction errors ///
- string constant REENTRANCY_ILLEGAL = "REENTRANCY_ILLEGAL"; // Recursive reentrancy is not allowed.
- string constant INVALID_TX_HASH = "INVALID_TX_HASH"; // Transaction has already been executed.
- string constant INVALID_TX_SIGNATURE = "INVALID_TX_SIGNATURE"; // Signature validation failed.
- string constant FAILED_EXECUTION = "FAILED_EXECUTION"; // Transaction execution failed.
-
- /// registerAssetProxy errors ///
- string constant ASSET_PROXY_ALREADY_EXISTS = "ASSET_PROXY_ALREADY_EXISTS"; // AssetProxy with same id already exists.
-
- /// dispatchTransferFrom errors ///
- string constant ASSET_PROXY_DOES_NOT_EXIST = "ASSET_PROXY_DOES_NOT_EXIST"; // No assetProxy registered at given id.
- string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Asset transfer unsuccesful.
-
- /// Length validation errors ///
- string constant LENGTH_GREATER_THAN_0_REQUIRED = "LENGTH_GREATER_THAN_0_REQUIRED"; // Byte array must have a length greater than 0.
- string constant LENGTH_GREATER_THAN_3_REQUIRED = "LENGTH_GREATER_THAN_3_REQUIRED"; // Byte array must have a length greater than 3.
- string constant LENGTH_0_REQUIRED = "LENGTH_0_REQUIRED"; // Byte array must have a length of 0.
- string constant LENGTH_65_REQUIRED = "LENGTH_65_REQUIRED"; // Byte array must have a length of 65.
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol
deleted file mode 100644
index 659ae9a69..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibFillResults.sol
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-
- 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";
-
-
-contract LibFillResults is
- SafeMath
-{
- struct FillResults {
- uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled.
- uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled.
- uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s).
- uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s).
- }
-
- struct MatchedFillResults {
- FillResults left; // Amounts filled and fees paid of left order.
- FillResults right; // Amounts filled and fees paid of right order.
- uint256 leftMakerAssetSpreadAmount; // Spread between price of left and right order, denominated in the left order's makerAsset, paid to taker.
- }
-
- /// @dev Adds properties of both FillResults instances.
- /// Modifies the first FillResults instance specified.
- /// @param totalFillResults Fill results instance that will be added onto.
- /// @param singleFillResults Fill results instance that will be added to totalFillResults.
- function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- internal
- pure
- {
- totalFillResults.makerAssetFilledAmount = safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
- totalFillResults.takerAssetFilledAmount = safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
- totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid);
- totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid);
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol
deleted file mode 100644
index c0b85ea10..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibMath.sol
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
-
- 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";
-
-
-contract LibMath is
- SafeMath
-{
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded down.
- function safeGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- require(
- !isRoundingErrorFloor(
- numerator,
- denominator,
- target
- ),
- "ROUNDING_ERROR"
- );
-
- partialAmount = safeDiv(
- safeMul(numerator, target),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded up.
- function safeGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- require(
- !isRoundingErrorCeil(
- numerator,
- denominator,
- target
- ),
- "ROUNDING_ERROR"
- );
-
- // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
- // ceil(a / b) = floor((a + b - 1) / b)
- // To implement `ceil(a / b)` using safeDiv.
- partialAmount = safeDiv(
- safeAdd(
- safeMul(numerator, target),
- safeSub(denominator, 1)
- ),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded down.
- function getPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- partialAmount = safeDiv(
- safeMul(numerator, target),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded up.
- function getPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
- // ceil(a / b) = floor((a + b - 1) / b)
- // To implement `ceil(a / b)` using safeDiv.
- partialAmount = safeDiv(
- safeAdd(
- safeMul(numerator, target),
- safeSub(denominator, 1)
- ),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Checks if rounding error >= 0.1% when rounding down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function isRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (bool isError)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // The absolute rounding error is the difference between the rounded
- // value and the ideal value. The relative rounding error is the
- // absolute rounding error divided by the absolute value of the
- // ideal value. This is undefined when the ideal value is zero.
- //
- // The ideal value is `numerator * target / denominator`.
- // Let's call `numerator * target % denominator` the remainder.
- // The absolute error is `remainder / denominator`.
- //
- // When the ideal value is zero, we require the absolute error to
- // be zero. Fortunately, this is always the case. The ideal value is
- // zero iff `numerator == 0` and/or `target == 0`. In this case the
- // remainder and absolute error are also zero.
- if (target == 0 || numerator == 0) {
- return false;
- }
-
- // Otherwise, we want the relative rounding error to be strictly
- // less than 0.1%.
- // The relative error is `remainder / (numerator * target)`.
- // We want the relative error less than 1 / 1000:
- // remainder / (numerator * denominator) < 1 / 1000
- // or equivalently:
- // 1000 * remainder < numerator * target
- // so we have a rounding error iff:
- // 1000 * remainder >= numerator * target
- uint256 remainder = mulmod(
- target,
- numerator,
- denominator
- );
- isError = safeMul(1000, remainder) >= safeMul(numerator, target);
- return isError;
- }
-
- /// @dev Checks if rounding error >= 0.1% when rounding up.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function isRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (bool isError)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // See the comments in `isRoundingError`.
- if (target == 0 || numerator == 0) {
- // When either is zero, the ideal value and rounded value are zero
- // and there is no rounding error. (Although the relative error
- // is undefined.)
- return false;
- }
- // Compute remainder as before
- uint256 remainder = mulmod(
- target,
- numerator,
- denominator
- );
- remainder = safeSub(denominator, remainder) % denominator;
- isError = safeMul(1000, remainder) >= safeMul(numerator, target);
- return isError;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol b/packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol
deleted file mode 100644
index 0fe7c2161..000000000
--- a/packages/contracts/contracts/protocol/Exchange/libs/LibOrder.sol
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-
- 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 "./LibEIP712.sol";
-
-
-contract LibOrder is
- LibEIP712
-{
- // Hash for the EIP712 Order Schema
- bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(
- "Order(",
- "address makerAddress,",
- "address takerAddress,",
- "address feeRecipientAddress,",
- "address senderAddress,",
- "uint256 makerAssetAmount,",
- "uint256 takerAssetAmount,",
- "uint256 makerFee,",
- "uint256 takerFee,",
- "uint256 expirationTimeSeconds,",
- "uint256 salt,",
- "bytes makerAssetData,",
- "bytes takerAssetData",
- ")"
- ));
-
- // A valid order remains fillable until it is expired, fully filled, or cancelled.
- // An order's state is unaffected by external factors, like account balances.
- enum OrderStatus {
- INVALID, // Default value
- INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
- INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
- FILLABLE, // Order is fillable
- EXPIRED, // Order has already expired
- FULLY_FILLED, // Order is fully filled
- CANCELLED // Order has been cancelled
- }
-
- // solhint-disable max-line-length
- struct Order {
- address makerAddress; // Address that created the order.
- address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
- address feeRecipientAddress; // Address that will recieve fees when order is filled.
- address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.
- uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0.
- uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0.
- uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
- uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
- uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires.
- uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash.
- bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.
- bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.
- }
- // solhint-enable max-line-length
-
- struct OrderInfo {
- uint8 orderStatus; // Status that describes order's validity and fillability.
- bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).
- uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
- }
-
- /// @dev Calculates Keccak-256 hash of the order.
- /// @param order The order structure.
- /// @return Keccak-256 EIP712 hash of the order.
- function getOrderHash(Order memory order)
- internal
- view
- returns (bytes32 orderHash)
- {
- orderHash = hashEIP712Message(hashOrder(order));
- return orderHash;
- }
-
- /// @dev Calculates EIP712 hash of the order.
- /// @param order The order structure.
- /// @return EIP712 hash of the order.
- function hashOrder(Order memory order)
- internal
- pure
- returns (bytes32 result)
- {
- bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;
- bytes32 makerAssetDataHash = keccak256(order.makerAssetData);
- bytes32 takerAssetDataHash = keccak256(order.takerAssetData);
-
- // Assembly for more efficiently computing:
- // keccak256(abi.encodePacked(
- // EIP712_ORDER_SCHEMA_HASH,
- // bytes32(order.makerAddress),
- // bytes32(order.takerAddress),
- // bytes32(order.feeRecipientAddress),
- // bytes32(order.senderAddress),
- // order.makerAssetAmount,
- // order.takerAssetAmount,
- // order.makerFee,
- // order.takerFee,
- // order.expirationTimeSeconds,
- // order.salt,
- // keccak256(order.makerAssetData),
- // keccak256(order.takerAssetData)
- // ));
-
- assembly {
- // Calculate memory addresses that will be swapped out before hashing
- let pos1 := sub(order, 32)
- let pos2 := add(order, 320)
- let pos3 := add(order, 352)
-
- // Backup
- let temp1 := mload(pos1)
- let temp2 := mload(pos2)
- let temp3 := mload(pos3)
-
- // Hash in place
- mstore(pos1, schemaHash)
- mstore(pos2, makerAssetDataHash)
- mstore(pos3, takerAssetDataHash)
- result := keccak256(pos1, 416)
-
- // Restore
- mstore(pos1, temp1)
- mstore(pos2, temp2)
- mstore(pos3, temp3)
- }
- return result;
- }
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
deleted file mode 100644
index 0ddfca270..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-
- 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 "../interfaces/IAssetProxyDispatcher.sol";
-
-
-contract MAssetProxyDispatcher is
- IAssetProxyDispatcher
-{
- // Logs registration of new asset proxy
- event AssetProxyRegistered(
- bytes4 id, // Id of new registered AssetProxy.
- address assetProxy // Address of new registered AssetProxy.
- );
-
- /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetData Byte array encoded for the asset.
- /// @param from Address to transfer token from.
- /// @param to Address to transfer token to.
- /// @param amount Amount of token to transfer.
- function dispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- internal;
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol
deleted file mode 100644
index 742499568..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MExchangeCore.sol
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-import "../interfaces/IExchangeCore.sol";
-
-
-contract MExchangeCore is
- IExchangeCore
-{
- // Fill event is emitted whenever an order is filled.
- event Fill(
- address indexed makerAddress, // Address that created the order.
- address indexed feeRecipientAddress, // Address that received fees.
- address takerAddress, // Address that filled the order.
- address senderAddress, // Address that called the Exchange contract (msg.sender).
- uint256 makerAssetFilledAmount, // Amount of makerAsset sold by maker and bought by taker.
- uint256 takerAssetFilledAmount, // Amount of takerAsset sold by taker and bought by maker.
- uint256 makerFeePaid, // Amount of ZRX paid to feeRecipient by maker.
- uint256 takerFeePaid, // Amount of ZRX paid to feeRecipient by taker.
- bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getOrderHash).
- bytes makerAssetData, // Encoded data specific to makerAsset.
- bytes takerAssetData // Encoded data specific to takerAsset.
- );
-
- // Cancel event is emitted whenever an individual order is cancelled.
- event Cancel(
- address indexed makerAddress, // Address that created the order.
- address indexed feeRecipientAddress, // Address that would have recieved fees if order was filled.
- address senderAddress, // Address that called the Exchange contract (msg.sender).
- bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getOrderHash).
- bytes makerAssetData, // Encoded data specific to makerAsset.
- bytes takerAssetData // Encoded data specific to takerAsset.
- );
-
- // CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully.
- event CancelUpTo(
- address indexed makerAddress, // Orders cancelled must have been created by this address.
- address indexed senderAddress, // Orders cancelled must have a `senderAddress` equal to this address.
- uint256 orderEpoch // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled.
- );
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev After calling, the order can not be filled anymore.
- /// @param order Order struct containing order specifications.
- function cancelOrderInternal(LibOrder.Order memory order)
- internal;
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function updateFilledState(
- LibOrder.Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- LibFillResults.FillResults memory fillResults
- )
- internal;
-
- /// @dev Updates state with results of cancelling an order.
- /// State is only updated if the order is currently fillable.
- /// Otherwise, updating state would have no effect.
- /// @param order that was cancelled.
- /// @param orderHash Hash of order that was cancelled.
- function updateCancelledState(
- LibOrder.Order memory order,
- bytes32 orderHash
- )
- internal;
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAddress Address of order taker.
- /// @param signature Proof that the orders was created by its maker.
- function assertFillableOrder(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo,
- address takerAddress,
- bytes memory signature
- )
- internal
- view;
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo Status, orderHash, and amount already filled of order.
- /// @param takerAssetFillAmount Desired amount of order to fill by taker.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
- function assertValidFill(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo,
- uint256 takerAssetFillAmount,
- uint256 takerAssetFilledAmount,
- uint256 makerAssetFilledAmount
- )
- internal
- view;
-
- /// @dev Validates context for cancelOrder. Succeeds or throws.
- /// @param order to be cancelled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- function assertValidCancel(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo
- )
- internal
- view;
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function calculateFillResults(
- LibOrder.Order memory order,
- uint256 takerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.FillResults memory fillResults);
-
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol
deleted file mode 100644
index 96fa34bc0..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MMatchOrders.sol
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-import "../interfaces/IMatchOrders.sol";
-
-
-contract MMatchOrders is
- IMatchOrders
-{
- /// @dev Validates context for matchOrders. Succeeds or throws.
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- function assertValidMatch(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder
- )
- internal
- pure;
-
- /// @dev Calculates fill amounts for the matched orders.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the leftOrder order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
- /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
- /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
- function calculateMatchedFillResults(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- uint256 leftOrderTakerAssetFilledAmount,
- uint256 rightOrderTakerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.MatchedFillResults memory matchedFillResults);
-
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
deleted file mode 100644
index 1fe88b908..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MSignatureValidator.sol
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-
- 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 "../interfaces/ISignatureValidator.sol";
-
-
-contract MSignatureValidator is
- ISignatureValidator
-{
- event SignatureValidatorApproval(
- address indexed signerAddress, // Address that approves or disapproves a contract to verify signatures.
- address indexed validatorAddress, // Address of signature validator contract.
- bool approved // Approval or disapproval of validator contract.
- );
-
- // Allowed signature types.
- enum SignatureType {
- Illegal, // 0x00, default value
- Invalid, // 0x01
- EIP712, // 0x02
- EthSign, // 0x03
- Wallet, // 0x04
- Validator, // 0x05
- PreSigned, // 0x06
- NSignatureTypes // 0x07, number of signature types. Always leave at end.
- }
-
- /// @dev Verifies signature using logic defined by Wallet contract.
- /// @param hash Any 32 byte hash.
- /// @param walletAddress Address that should have signed the given hash
- /// and defines its own signature verification method.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidWalletSignature(
- bytes32 hash,
- address walletAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid);
-
- /// @dev Verifies signature using logic defined by Validator contract.
- /// @param validatorAddress Address of validator contract.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidValidatorSignature(
- address validatorAddress,
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol
deleted file mode 100644
index 4f61a4945..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MTransactions.sol
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-
- 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 "../interfaces/ITransactions.sol";
-
-
-contract MTransactions is
- ITransactions
-{
- // Hash for the EIP712 ZeroEx Transaction Schema
- bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = keccak256(abi.encodePacked(
- "ZeroExTransaction(",
- "uint256 salt,",
- "address signerAddress,",
- "bytes data",
- ")"
- ));
-
- /// @dev Calculates EIP712 hash of the Transaction.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @return EIP712 hash of the Transaction.
- function hashZeroExTransaction(
- uint256 salt,
- address signerAddress,
- bytes memory data
- )
- internal
- pure
- returns (bytes32 result);
-
- /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
- /// If calling a fill function, this address will represent the taker.
- /// If calling a cancel function, this address will represent the maker.
- /// @return Signer of 0x transaction if entry point is `executeTransaction`.
- /// `msg.sender` if entry point is any other function.
- function getCurrentContextAddress()
- internal
- view
- returns (address);
-}
diff --git a/packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol b/packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol
deleted file mode 100644
index 4adfbde01..000000000
--- a/packages/contracts/contracts/protocol/Exchange/mixins/MWrapperFunctions.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../libs/LibOrder.sol";
-import "../libs/LibFillResults.sol";
-import "../interfaces/IWrapperFunctions.sol";
-
-
-contract MWrapperFunctions is
- IWrapperFunctions
-{
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-}
diff --git a/packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol b/packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol
deleted file mode 100644
index 412c5d1ad..000000000
--- a/packages/contracts/contracts/test/DummyERC20Token/DummyERC20Token.sol
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-
- 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/Ownable/Ownable.sol";
-import "../../tokens/ERC20Token/MintableERC20Token.sol";
-
-
-contract DummyERC20Token is
- Ownable,
- MintableERC20Token
-{
- string public name;
- string public symbol;
- uint256 public decimals;
- uint256 public constant MAX_MINT_AMOUNT = 10000000000000000000000;
-
- constructor (
- string _name,
- string _symbol,
- uint256 _decimals,
- uint256 _totalSupply
- )
- public
- {
- name = _name;
- symbol = _symbol;
- decimals = _decimals;
- _totalSupply = _totalSupply;
- balances[msg.sender] = _totalSupply;
- }
-
- /// @dev Sets the balance of target address
- /// @param _target Address or which balance will be updated
- /// @param _value New balance of target address
- function setBalance(address _target, uint256 _value)
- external
- onlyOwner
- {
- uint256 currBalance = balances[_target];
- if (_value < currBalance) {
- _totalSupply = safeSub(_totalSupply, safeSub(currBalance, _value));
- } else {
- _totalSupply = safeAdd(_totalSupply, safeSub(_value, currBalance));
- }
- balances[_target] = _value;
- }
-
- /// @dev Mints new tokens for sender
- /// @param _value Amount of tokens to mint
- function mint(uint256 _value)
- external
- {
- require(
- _value <= MAX_MINT_AMOUNT,
- "VALUE_TOO_LARGE"
- );
-
- _mint(msg.sender, _value);
- }
-}
diff --git a/packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol b/packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol
deleted file mode 100644
index 733d4437e..000000000
--- a/packages/contracts/contracts/test/DummyERC20Token/DummyMultipleReturnERC20Token.sol
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
- 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 "./DummyERC20Token.sol";
-
-
-// solhint-disable no-empty-blocks
-contract DummyMultipleReturnERC20Token is
- DummyERC20Token
-{
- constructor (
- string _name,
- string _symbol,
- uint256 _decimals,
- uint256 _totalSupply
- )
- public
- DummyERC20Token(
- _name,
- _symbol,
- _decimals,
- _totalSupply
- )
- {}
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return 64 bytes (equiavalent to true, true)
- assembly {
- mstore(0, 1)
- mstore(32, 1)
- return(0, 64)
- }
- }
-}
-
diff --git a/packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol b/packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol
deleted file mode 100644
index e16825a16..000000000
--- a/packages/contracts/contracts/test/DummyERC20Token/DummyNoReturnERC20Token.sol
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-
- 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 "./DummyERC20Token.sol";
-
-
-// solhint-disable no-empty-blocks
-contract DummyNoReturnERC20Token is
- DummyERC20Token
-{
- constructor (
- string _name,
- string _symbol,
- uint256 _decimals,
- uint256 _totalSupply
- )
- public
- DummyERC20Token(
- _name,
- _symbol,
- _decimals,
- _totalSupply
- )
- {}
-
- /// @dev send `value` token to `to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transfer(address _to, uint256 _value)
- external
- returns (bool)
- {
- require(
- balances[msg.sender] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[msg.sender] -= _value;
- balances[_to] += _value;
-
- emit Transfer(
- msg.sender,
- _to,
- _value
- );
-
- // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
- assembly {
- return(0, 0)
- }
- }
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- require(
- balances[_from] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- allowed[_from][msg.sender] >= _value,
- "ERC20_INSUFFICIENT_ALLOWANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[_to] += _value;
- balances[_from] -= _value;
- allowed[_from][msg.sender] -= _value;
-
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
- assembly {
- return(0, 0)
- }
- }
-}
-
diff --git a/packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol b/packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol
deleted file mode 100644
index 6c8371559..000000000
--- a/packages/contracts/contracts/test/DummyERC721Receiver/DummyERC721Receiver.sol
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-
- 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 "../../tokens/ERC721Token/IERC721Receiver.sol";
-
-
-contract DummyERC721Receiver is
- IERC721Receiver
-{
- // Function selector for ERC721Receiver.onERC721Received
- // 0x150b7a02
- bytes4 constant internal ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
-
- event TokenReceived(
- address operator,
- address from,
- uint256 tokenId,
- bytes data
- );
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes _data
- )
- external
- returns (bytes4)
- {
- emit TokenReceived(
- _operator,
- _from,
- _tokenId,
- _data
- );
- return ERC721_RECEIVED;
- }
-}
diff --git a/packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol b/packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol
deleted file mode 100644
index 309633bf5..000000000
--- a/packages/contracts/contracts/test/DummyERC721Receiver/InvalidERC721Receiver.sol
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-
- 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 "../../tokens/ERC721Token/IERC721Receiver.sol";
-
-
-contract InvalidERC721Receiver is
- IERC721Receiver
-{
- // Actual function signature is `onERC721Received(address,address,uint256,bytes)`
- bytes4 constant internal INVALID_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,uint256,bytes)"));
-
- event TokenReceived(
- address operator,
- address from,
- uint256 tokenId,
- bytes data
- );
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes _data
- )
- external
- returns (bytes4)
- {
- emit TokenReceived(
- _operator,
- _from,
- _tokenId,
- _data
- );
- return INVALID_ERC721_RECEIVED;
- }
-}
diff --git a/packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol b/packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol
deleted file mode 100644
index ac9068d1d..000000000
--- a/packages/contracts/contracts/test/DummyERC721Token/DummyERC721Token.sol
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-
- 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 "../../tokens/ERC721Token/MintableERC721Token.sol";
-import "../../utils/Ownable/Ownable.sol";
-
-
-// solhint-disable no-empty-blocks
-contract DummyERC721Token is
- Ownable,
- MintableERC721Token
-{
- string public name;
- string public symbol;
-
- constructor (
- string _name,
- string _symbol
- )
- public
- {
- name = _name;
- symbol = _symbol;
- }
-
- /// @dev Function to mint a new token
- /// Reverts if the given token ID already exists
- /// @param _to Address of the beneficiary that will own the minted token
- /// @param _tokenId ID of the token to be minted by the msg.sender
- function mint(address _to, uint256 _tokenId)
- external
- {
- _mint(_to, _tokenId);
- }
-
- /// @dev Function to burn a token
- /// Reverts if the given token ID doesn't exist or not called by contract owner
- /// @param _owner Owner of token with given token ID
- /// @param _tokenId ID of the token to be burned by the msg.sender
- function burn(address _owner, uint256 _tokenId)
- external
- onlyOwner
- {
- _burn(_owner, _tokenId);
- }
-}
diff --git a/packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol b/packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol
deleted file mode 100644
index 99dd47a78..000000000
--- a/packages/contracts/contracts/test/ReentrantERC20Token/ReentrantERC20Token.sol
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../utils/LibBytes/LibBytes.sol";
-import "../../tokens/ERC20Token/ERC20Token.sol";
-import "../../protocol/Exchange/interfaces/IExchange.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-
-
-// solhint-disable no-unused-vars
-contract ReentrantERC20Token is
- ERC20Token
-{
- using LibBytes for bytes;
-
- // solhint-disable-next-line var-name-mixedcase
- IExchange internal EXCHANGE;
-
- bytes internal constant REENTRANCY_ILLEGAL_REVERT_REASON = abi.encodeWithSelector(
- bytes4(keccak256("Error(string)")),
- "REENTRANCY_ILLEGAL"
- );
-
- // All of these functions are potentially vulnerable to reentrancy
- // We do not test any "noThrow" functions because `fillOrderNoThrow` makes a delegatecall to `fillOrder`
- enum ExchangeFunction {
- FILL_ORDER,
- FILL_OR_KILL_ORDER,
- BATCH_FILL_ORDERS,
- BATCH_FILL_OR_KILL_ORDERS,
- MARKET_BUY_ORDERS,
- MARKET_SELL_ORDERS,
- MATCH_ORDERS,
- CANCEL_ORDER,
- BATCH_CANCEL_ORDERS,
- CANCEL_ORDERS_UP_TO,
- SET_SIGNATURE_VALIDATOR_APPROVAL
- }
-
- uint8 internal currentFunctionId = 0;
-
- constructor (address _exchange)
- public
- {
- EXCHANGE = IExchange(_exchange);
- }
-
- /// @dev Set the current function that will be called when `transferFrom` is called.
- /// @param _currentFunctionId Id that corresponds to function name.
- function setCurrentFunction(uint8 _currentFunctionId)
- external
- {
- currentFunctionId = _currentFunctionId;
- }
-
- /// @dev A version of `transferFrom` that attempts to reenter the Exchange contract.
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- // This order would normally be invalid, but it will be used strictly for testing reentrnacy.
- // Any reentrancy checks will happen before any other checks that invalidate the order.
- LibOrder.Order memory order;
-
- // Initialize remaining null parameters
- bytes memory signature;
- LibOrder.Order[] memory orders;
- uint256[] memory takerAssetFillAmounts;
- bytes[] memory signatures;
- bytes memory calldata;
-
- // Create calldata for function that corresponds to currentFunctionId
- if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.fillOrder.selector,
- order,
- 0,
- signature
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.FILL_OR_KILL_ORDER)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.fillOrKillOrder.selector,
- order,
- 0,
- signature
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.batchFillOrders.selector,
- orders,
- takerAssetFillAmounts,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_OR_KILL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.batchFillOrKillOrders.selector,
- orders,
- takerAssetFillAmounts,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.marketBuyOrders.selector,
- orders,
- 0,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.marketSellOrders.selector,
- orders,
- 0,
- signatures
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.MATCH_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.matchOrders.selector,
- order,
- order,
- signature,
- signature
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDER)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.cancelOrder.selector,
- order
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_CANCEL_ORDERS)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.batchCancelOrders.selector,
- orders
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDERS_UP_TO)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.cancelOrdersUpTo.selector,
- 0
- );
- } else if (currentFunctionId == uint8(ExchangeFunction.SET_SIGNATURE_VALIDATOR_APPROVAL)) {
- calldata = abi.encodeWithSelector(
- EXCHANGE.setSignatureValidatorApproval.selector,
- address(0),
- false
- );
- }
-
- // Call Exchange function, swallow error
- address(EXCHANGE).call(calldata);
-
- // Revert reason is 100 bytes
- bytes memory returnData = new bytes(100);
-
- // Copy return data
- assembly {
- returndatacopy(add(returnData, 32), 0, 100)
- }
-
- // Revert if function reverted with REENTRANCY_ILLEGAL error
- require(!REENTRANCY_ILLEGAL_REVERT_REASON.equals(returnData));
-
- // Transfer will return true if function failed for any other reason
- return true;
- }
-} \ No newline at end of file
diff --git a/packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol b/packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
deleted file mode 100644
index ad71fc9a1..000000000
--- a/packages/contracts/contracts/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
- 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 "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
-
-
-contract TestAssetProxyDispatcher is
- MixinAssetProxyDispatcher
-{
- function publicDispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- public
- {
- dispatchTransferFrom(assetData, from, to, amount);
- }
-}
diff --git a/packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol b/packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
deleted file mode 100644
index 52c66cb56..000000000
--- a/packages/contracts/contracts/test/TestAssetProxyOwner/TestAssetProxyOwner.sol
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-
- 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 "../../protocol/AssetProxyOwner/AssetProxyOwner.sol";
-
-
-// solhint-disable no-empty-blocks
-contract TestAssetProxyOwner is
- AssetProxyOwner
-{
- constructor (
- address[] memory _owners,
- address[] memory _assetProxyContracts,
- uint256 _required,
- uint256 _secondsTimeLocked
- )
- public
- AssetProxyOwner(_owners, _assetProxyContracts, _required, _secondsTimeLocked)
- {}
-
- function testValidRemoveAuthorizedAddressAtIndexTx(uint256 id)
- public
- view
- validRemoveAuthorizedAddressAtIndexTx(id)
- returns (bool)
- {
- // Do nothing. We expect reverts through the modifier
- return true;
- }
-
- /// @dev Compares first 4 bytes of byte array to `removeAuthorizedAddressAtIndex` function selector.
- /// @param data Transaction data.
- /// @return Successful if data is a call to `removeAuthorizedAddressAtIndex`.
- function isFunctionRemoveAuthorizedAddressAtIndex(bytes memory data)
- public
- pure
- returns (bool)
- {
- return data.readBytes4(0) == REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR;
- }
-}
diff --git a/packages/contracts/contracts/test/TestConstants/TestConstants.sol b/packages/contracts/contracts/test/TestConstants/TestConstants.sol
deleted file mode 100644
index 1275d007b..000000000
--- a/packages/contracts/contracts/test/TestConstants/TestConstants.sol
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-
- 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/LibBytes/LibBytes.sol";
-
-
-// solhint-disable max-line-length
-contract TestConstants {
-
- using LibBytes for bytes;
-
- bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
-
- address constant internal KOVAN_ZRX_ADDRESS = 0x6Ff6C0Ff1d68b964901F986d4C9FA3ac68346570;
- bytes constant internal KOVAN_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70";
-
- address constant internal MAINNET_ZRX_ADDRESS = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
- bytes constant public MAINNET_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98";
-
- function assertValidZrxAssetData()
- public
- pure
- returns (bool)
- {
- bytes memory kovanZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, KOVAN_ZRX_ADDRESS);
- require(
- kovanZrxAssetData.equals(KOVAN_ZRX_ASSET_DATA),
- "INVALID_KOVAN_ZRX_ASSET_DATA"
- );
-
- bytes memory mainetZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, MAINNET_ZRX_ADDRESS);
- require(
- mainetZrxAssetData.equals(MAINNET_ZRX_ASSET_DATA),
- "INVALID_MAINNET_ZRX_ASSET_DATA"
- );
-
- return true;
- }
-}
-// solhint-enable max-line-length \ No newline at end of file
diff --git a/packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol b/packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol
deleted file mode 100644
index 27187f8f8..000000000
--- a/packages/contracts/contracts/test/TestExchangeInternals/TestExchangeInternals.sol
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../protocol/Exchange/Exchange.sol";
-
-
-// solhint-disable no-empty-blocks
-contract TestExchangeInternals is
- Exchange
-{
- constructor ()
- public
- Exchange("")
- {}
-
- /// @dev Adds properties of both FillResults instances.
- /// Modifies the first FillResults instance specified.
- /// Note that this function has been modified from the original
- // internal version to return the FillResults.
- /// @param totalFillResults Fill results instance that will be added onto.
- /// @param singleFillResults Fill results instance that will be added to totalFillResults.
- /// @return newTotalFillResults The result of adding singleFillResults to totalFilResults.
- function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- public
- pure
- returns (FillResults memory)
- {
- addFillResults(totalFillResults, singleFillResults);
- return totalFillResults;
- }
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function publicCalculateFillResults(
- Order memory order,
- uint256 takerAssetFilledAmount
- )
- public
- pure
- returns (FillResults memory fillResults)
- {
- return calculateFillResults(order, takerAssetFilledAmount);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicSafeGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return safeGetPartialAmountFloor(numerator, denominator, target);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicSafeGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return safeGetPartialAmountCeil(numerator, denominator, target);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return getPartialAmountFloor(numerator, denominator, target);
- }
-
- /// @dev Calculates partial value given a numerator and denominator.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target.
- function publicGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- return getPartialAmountCeil(numerator, denominator, target);
- }
-
- /// @dev Checks if rounding error >= 0.1%.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function publicIsRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- return isRoundingErrorFloor(numerator, denominator, target);
- }
-
- /// @dev Checks if rounding error >= 0.1%.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function publicIsRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- return isRoundingErrorCeil(numerator, denominator, target);
- }
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function publicUpdateFilledState(
- Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- FillResults memory fillResults
- )
- public
- {
- updateFilledState(
- order,
- takerAddress,
- orderHash,
- orderTakerAssetFilledAmount,
- fillResults
- );
- }
-}
diff --git a/packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol b/packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol
deleted file mode 100644
index 00d861e61..000000000
--- a/packages/contracts/contracts/test/TestLibBytes/TestLibBytes.sol
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
-
- 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/LibBytes/LibBytes.sol";
-
-
-contract TestLibBytes {
-
- using LibBytes for bytes;
-
- /// @dev Pops the last byte off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The byte that was popped off.
- function publicPopLastByte(bytes memory b)
- public
- pure
- returns (bytes memory, bytes1 result)
- {
- result = b.popLastByte();
- return (b, result);
- }
-
- /// @dev Pops the last 20 bytes off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The 20 byte address that was popped off.
- function publicPopLast20Bytes(bytes memory b)
- public
- pure
- returns (bytes memory, address result)
- {
- result = b.popLast20Bytes();
- return (b, result);
- }
-
- /// @dev Tests equality of two byte arrays.
- /// @param lhs First byte array to compare.
- /// @param rhs Second byte array to compare.
- /// @return True if arrays are the same. False otherwise.
- function publicEquals(bytes memory lhs, bytes memory rhs)
- public
- pure
- returns (bool equal)
- {
- equal = lhs.equals(rhs);
- return equal;
- }
-
- function publicEqualsPop1(bytes memory lhs, bytes memory rhs)
- public
- pure
- returns (bool equal)
- {
- lhs.popLastByte();
- rhs.popLastByte();
- equal = lhs.equals(rhs);
- return equal;
- }
-
- /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
- /// @param dest Byte array that will be overwritten with source bytes.
- /// @param source Byte array to copy onto dest bytes.
- function publicDeepCopyBytes(
- bytes memory dest,
- bytes memory source
- )
- public
- pure
- returns (bytes memory)
- {
- LibBytes.deepCopyBytes(dest, source);
- return dest;
- }
-
- /// @dev Reads an address from a position in a byte array.
- /// @param b Byte array containing an address.
- /// @param index Index in byte array of address.
- /// @return address from byte array.
- function publicReadAddress(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (address result)
- {
- result = b.readAddress(index);
- return result;
- }
-
- /// @dev Writes an address into a specific position in a byte array.
- /// @param b Byte array to insert address into.
- /// @param index Index in byte array of address.
- /// @param input Address to put into byte array.
- function publicWriteAddress(
- bytes memory b,
- uint256 index,
- address input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeAddress(index, input);
- return b;
- }
-
- /// @dev Reads a bytes32 value from a position in a byte array.
- /// @param b Byte array containing a bytes32 value.
- /// @param index Index in byte array of bytes32 value.
- /// @return bytes32 value from byte array.
- function publicReadBytes32(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (bytes32 result)
- {
- result = b.readBytes32(index);
- return result;
- }
-
- /// @dev Writes a bytes32 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes32 to put into byte array.
- function publicWriteBytes32(
- bytes memory b,
- uint256 index,
- bytes32 input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeBytes32(index, input);
- return b;
- }
-
- /// @dev Reads a uint256 value from a position in a byte array.
- /// @param b Byte array containing a uint256 value.
- /// @param index Index in byte array of uint256 value.
- /// @return uint256 value from byte array.
- function publicReadUint256(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (uint256 result)
- {
- result = b.readUint256(index);
- return result;
- }
-
- /// @dev Writes a uint256 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input uint256 to put into byte array.
- function publicWriteUint256(
- bytes memory b,
- uint256 index,
- uint256 input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeUint256(index, input);
- return b;
- }
-
- /// @dev Reads an unpadded bytes4 value from a position in a byte array.
- /// @param b Byte array containing a bytes4 value.
- /// @param index Index in byte array of bytes4 value.
- /// @return bytes4 value from byte array.
- function publicReadBytes4(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (bytes4 result)
- {
- result = b.readBytes4(index);
- return result;
- }
-
- /// @dev Reads nested bytes from a specific position.
- /// @param b Byte array containing nested bytes.
- /// @param index Index of nested bytes.
- /// @return result Nested bytes.
- function publicReadBytesWithLength(
- bytes memory b,
- uint256 index
- )
- public
- pure
- returns (bytes memory result)
- {
- result = b.readBytesWithLength(index);
- return result;
- }
-
- /// @dev Inserts bytes at a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes to insert.
- /// @return b Updated input byte array
- function publicWriteBytesWithLength(
- bytes memory b,
- uint256 index,
- bytes memory input
- )
- public
- pure
- returns (bytes memory)
- {
- b.writeBytesWithLength(index, input);
- return b;
- }
-
- /// @dev Copies a block of memory from one location to another.
- /// @param mem Memory contents we want to apply memCopy to
- /// @param dest Destination offset into <mem>.
- /// @param source Source offset into <mem>.
- /// @param length Length of bytes to copy from <source> to <dest>
- /// @return mem Memory contents after calling memCopy.
- function testMemcpy(
- bytes mem,
- uint256 dest,
- uint256 source,
- uint256 length
- )
- public // not external, we need input in memory
- pure
- returns (bytes)
- {
- // Sanity check. Overflows are not checked.
- require(source + length <= mem.length);
- require(dest + length <= mem.length);
-
- // Get pointer to memory contents
- uint256 offset = mem.contentAddress();
-
- // Execute memCopy adjusted for memory array location
- LibBytes.memCopy(offset + dest, offset + source, length);
-
- // Return modified memory contents
- return mem;
- }
-}
diff --git a/packages/contracts/contracts/test/TestLibs/TestLibs.sol b/packages/contracts/contracts/test/TestLibs/TestLibs.sol
deleted file mode 100644
index a10f981fc..000000000
--- a/packages/contracts/contracts/test/TestLibs/TestLibs.sol
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-
- 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;
-pragma experimental ABIEncoderV2;
-
-import "../../protocol/Exchange/libs/LibMath.sol";
-import "../../protocol/Exchange/libs/LibOrder.sol";
-import "../../protocol/Exchange/libs/LibFillResults.sol";
-import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
-
-
-contract TestLibs is
- LibMath,
- LibOrder,
- LibFillResults,
- LibAbiEncoder
-{
- function publicAbiEncodeFillOrder(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- pure
- returns (bytes memory fillOrderCalldata)
- {
- fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillOrderCalldata;
- }
-
- function publicGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- partialAmount = getPartialAmountFloor(
- numerator,
- denominator,
- target
- );
- return partialAmount;
- }
-
- function publicGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (uint256 partialAmount)
- {
- partialAmount = getPartialAmountCeil(
- numerator,
- denominator,
- target
- );
- return partialAmount;
- }
-
- function publicIsRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- isError = isRoundingErrorFloor(
- numerator,
- denominator,
- target
- );
- return isError;
- }
-
- function publicIsRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- public
- pure
- returns (bool isError)
- {
- isError = isRoundingErrorCeil(
- numerator,
- denominator,
- target
- );
- return isError;
- }
-
- function publicGetOrderHash(Order memory order)
- public
- view
- returns (bytes32 orderHash)
- {
- orderHash = getOrderHash(order);
- return orderHash;
- }
-
- function getOrderSchemaHash()
- public
- pure
- returns (bytes32)
- {
- return EIP712_ORDER_SCHEMA_HASH;
- }
-
- function getDomainSeparatorSchemaHash()
- public
- pure
- returns (bytes32)
- {
- return EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH;
- }
-
- function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- public
- pure
- returns (FillResults memory)
- {
- addFillResults(totalFillResults, singleFillResults);
- return totalFillResults;
- }
-}
diff --git a/packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol b/packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol
deleted file mode 100644
index ea3e2de59..000000000
--- a/packages/contracts/contracts/test/TestSignatureValidator/TestSignatureValidator.sol
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-
- 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 "../../protocol/Exchange/MixinSignatureValidator.sol";
-import "../../protocol/Exchange/MixinTransactions.sol";
-
-
-contract TestSignatureValidator is
- MixinSignatureValidator,
- MixinTransactions
-{
- function publicIsValidSignature(
- bytes32 hash,
- address signer,
- bytes memory signature
- )
- public
- view
- returns (bool isValid)
- {
- isValid = isValidSignature(
- hash,
- signer,
- signature
- );
- return isValid;
- }
-}
diff --git a/packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol b/packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol
deleted file mode 100644
index 41aab01c8..000000000
--- a/packages/contracts/contracts/test/TestStaticCallReceiver/TestStaticCallReceiver.sol
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-
- 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 "../../tokens/ERC20Token/IERC20Token.sol";
-
-
-// solhint-disable no-unused-vars
-contract TestStaticCallReceiver {
-
- uint256 internal state = 1;
-
- /// @dev Updates state and returns true. Intended to be used with `Validator` signature type.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- returns (bool isValid)
- {
- updateState();
- return true;
- }
-
- /// @dev Updates state and returns true. Intended to be used with `Wallet` signature type.
- /// @param hash Message hash that is signed.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- bytes signature
- )
- external
- returns (bool isValid)
- {
- updateState();
- return true;
- }
-
- /// @dev Approves an ERC20 token to spend tokens from this address.
- /// @param token Address of ERC20 token.
- /// @param spender Address that will spend tokens.
- /// @param value Amount of tokens spender is approved to spend.
- function approveERC20(
- address token,
- address spender,
- uint256 value
- )
- external
- {
- IERC20Token(token).approve(spender, value);
- }
-
- /// @dev Increments state variable.
- function updateState()
- internal
- {
- state++;
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol
deleted file mode 100644
index 725d304df..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/ERC20Token.sol
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
-
- 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 "./IERC20Token.sol";
-
-
-contract ERC20Token is
- IERC20Token
-{
- mapping (address => uint256) internal balances;
- mapping (address => mapping (address => uint256)) internal allowed;
-
- uint256 internal _totalSupply;
-
- /// @dev send `value` token to `to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transfer(address _to, uint256 _value)
- external
- returns (bool)
- {
- require(
- balances[msg.sender] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[msg.sender] -= _value;
- balances[_to] += _value;
-
- emit Transfer(
- msg.sender,
- _to,
- _value
- );
-
- return true;
- }
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- require(
- balances[_from] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- allowed[_from][msg.sender] >= _value,
- "ERC20_INSUFFICIENT_ALLOWANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[_to] += _value;
- balances[_from] -= _value;
- allowed[_from][msg.sender] -= _value;
-
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- return true;
- }
-
- /// @dev `msg.sender` approves `_spender` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of wei to be approved for transfer
- /// @return Always true if the call has enough gas to complete execution
- function approve(address _spender, uint256 _value)
- external
- returns (bool)
- {
- allowed[msg.sender][_spender] = _value;
- emit Approval(
- msg.sender,
- _spender,
- _value
- );
- return true;
- }
-
- /// @dev Query total supply of token
- /// @return Total supply of token
- function totalSupply()
- external
- view
- returns (uint256)
- {
- return _totalSupply;
- }
-
- /// @dev Query the balance of owner
- /// @param _owner The address from which the balance will be retrieved
- /// @return Balance of owner
- function balanceOf(address _owner)
- external
- view
- returns (uint256)
- {
- return balances[_owner];
- }
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender)
- external
- view
- returns (uint256)
- {
- return allowed[_owner][_spender];
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol
deleted file mode 100644
index 258d47393..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/IERC20Token.sol
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
- 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;
-
-
-contract IERC20Token {
-
- // solhint-disable no-simple-event-func-name
- event Transfer(
- address indexed _from,
- address indexed _to,
- uint256 _value
- );
-
- event Approval(
- address indexed _owner,
- address indexed _spender,
- uint256 _value
- );
-
- /// @dev send `value` token to `to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transfer(address _to, uint256 _value)
- external
- returns (bool);
-
- /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return True if transfer was successful
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool);
-
- /// @dev `msg.sender` approves `_spender` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of wei to be approved for transfer
- /// @return Always true if the call has enough gas to complete execution
- function approve(address _spender, uint256 _value)
- external
- returns (bool);
-
- /// @dev Query total supply of token
- /// @return Total supply of token
- function totalSupply()
- external
- view
- returns (uint256);
-
- /// @param _owner The address from which the balance will be retrieved
- /// @return Balance of owner
- function balanceOf(address _owner)
- external
- view
- returns (uint256);
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender)
- external
- view
- returns (uint256);
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol
deleted file mode 100644
index 9dc924422..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/MintableERC20Token.sol
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-
- 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 "./UnlimitedAllowanceERC20Token.sol";
-
-
-contract MintableERC20Token is
- SafeMath,
- UnlimitedAllowanceERC20Token
-{
- /// @dev Mints new tokens
- /// @param _to Address of the beneficiary that will own the minted token
- /// @param _value Amount of tokens to mint
- function _mint(address _to, uint256 _value)
- internal
- {
- balances[_to] = safeAdd(_value, balances[_to]);
- _totalSupply = safeAdd(_totalSupply, _value);
-
- emit Transfer(
- address(0),
- _to,
- _value
- );
- }
-
- /// @dev Mints new tokens
- /// @param _owner Owner of tokens that will be burned
- /// @param _value Amount of tokens to burn
- function _burn(address _owner, uint256 _value)
- internal
- {
- balances[_owner] = safeSub(balances[_owner], _value);
- _totalSupply = safeSub(_totalSupply, _value);
-
- emit Transfer(
- _owner,
- address(0),
- _value
- );
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
deleted file mode 100644
index 2e5bd4348..000000000
--- a/packages/contracts/contracts/tokens/ERC20Token/UnlimitedAllowanceERC20Token.sol
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-
- 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 "../ERC20Token/ERC20Token.sol";
-
-
-contract UnlimitedAllowanceERC20Token is
- ERC20Token
-{
- uint256 constant internal MAX_UINT = 2**256 - 1;
-
- /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717
- /// @param _from Address to transfer from.
- /// @param _to Address to transfer to.
- /// @param _value Amount to transfer.
- /// @return Success of transfer.
- function transferFrom(
- address _from,
- address _to,
- uint256 _value
- )
- external
- returns (bool)
- {
- uint256 allowance = allowed[_from][msg.sender];
- require(
- balances[_from] >= _value,
- "ERC20_INSUFFICIENT_BALANCE"
- );
- require(
- allowance >= _value,
- "ERC20_INSUFFICIENT_ALLOWANCE"
- );
- require(
- balances[_to] + _value >= balances[_to],
- "UINT256_OVERFLOW"
- );
-
- balances[_to] += _value;
- balances[_from] -= _value;
- if (allowance < MAX_UINT) {
- allowed[_from][msg.sender] -= _value;
- }
-
- emit Transfer(
- _from,
- _to,
- _value
- );
-
- return true;
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol b/packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol
deleted file mode 100644
index 530f080c0..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/ERC721Token.sol
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
-
- 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 "./IERC721Token.sol";
-import "./IERC721Receiver.sol";
-import "../../utils/SafeMath/SafeMath.sol";
-
-
-contract ERC721Token is
- IERC721Token,
- SafeMath
-{
- // Function selector for ERC721Receiver.onERC721Received
- // 0x150b7a02
- bytes4 constant internal ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
-
- // Mapping of tokenId => owner
- mapping (uint256 => address) internal owners;
-
- // Mapping of tokenId => approved address
- mapping (uint256 => address) internal approvals;
-
- // Mapping of owner => number of tokens owned
- mapping (address => uint256) internal balances;
-
- // Mapping of owner => operator => approved
- mapping (address => mapping (address => bool)) internal operatorApprovals;
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// operator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT. When transfer is complete, this function
- /// checks if `_to` is a smart contract (code size > 0). If so, it calls
- /// `onERC721Received` on `_to` and throws if the return value is not
- /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- /// @param _data Additional data with no specified format, sent in call to `_to`
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId,
- bytes _data
- )
- external
- {
- transferFrom(
- _from,
- _to,
- _tokenId
- );
-
- uint256 receiverCodeSize;
- assembly {
- receiverCodeSize := extcodesize(_to)
- }
- if (receiverCodeSize > 0) {
- bytes4 selector = IERC721Receiver(_to).onERC721Received(
- msg.sender,
- _from,
- _tokenId,
- _data
- );
- require(
- selector == ERC721_RECEIVED,
- "ERC721_INVALID_SELECTOR"
- );
- }
- }
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev This works identically to the other function with an extra data parameter,
- /// except this function just sets data to "".
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- external
- {
- transferFrom(
- _from,
- _to,
- _tokenId
- );
-
- uint256 receiverCodeSize;
- assembly {
- receiverCodeSize := extcodesize(_to)
- }
- if (receiverCodeSize > 0) {
- bytes4 selector = IERC721Receiver(_to).onERC721Received(
- msg.sender,
- _from,
- _tokenId,
- ""
- );
- require(
- selector == ERC721_RECEIVED,
- "ERC721_INVALID_SELECTOR"
- );
- }
- }
-
- /// @notice Change or reaffirm the approved address for an NFT
- /// @dev The zero address indicates there is no approved address.
- /// Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param _approved The new approved NFT controller
- /// @param _tokenId The NFT to approve
- function approve(address _approved, uint256 _tokenId)
- external
- {
- address owner = ownerOf(_tokenId);
- require(
- msg.sender == owner || isApprovedForAll(owner, msg.sender),
- "ERC721_INVALID_SENDER"
- );
-
- approvals[_tokenId] = _approved;
- emit Approval(
- owner,
- _approved,
- _tokenId
- );
- }
-
- /// @notice Enable or disable approval for a third party ("operator") to manage
- /// all of `msg.sender`'s assets
- /// @dev Emits the ApprovalForAll event. The contract MUST allow
- /// multiple operators per owner.
- /// @param _operator Address to add to the set of authorized operators
- /// @param _approved True if the operator is approved, false to revoke approval
- function setApprovalForAll(address _operator, bool _approved)
- external
- {
- operatorApprovals[msg.sender][_operator] = _approved;
- emit ApprovalForAll(
- msg.sender,
- _operator,
- _approved
- );
- }
-
- /// @notice Count all NFTs assigned to an owner
- /// @dev NFTs assigned to the zero address are considered invalid, and this
- /// function throws for queries about the zero address.
- /// @param _owner An address for whom to query the balance
- /// @return The number of NFTs owned by `_owner`, possibly zero
- function balanceOf(address _owner)
- external
- view
- returns (uint256)
- {
- require(
- _owner != address(0),
- "ERC721_ZERO_OWNER"
- );
- return balances[_owner];
- }
-
- /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
- /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
- /// THEY MAY BE PERMANENTLY LOST
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// operator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function transferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- public
- {
- require(
- _to != address(0),
- "ERC721_ZERO_TO_ADDRESS"
- );
-
- address owner = ownerOf(_tokenId);
- require(
- _from == owner,
- "ERC721_OWNER_MISMATCH"
- );
-
- address spender = msg.sender;
- address approvedAddress = getApproved(_tokenId);
- require(
- spender == owner ||
- isApprovedForAll(owner, spender) ||
- approvedAddress == spender,
- "ERC721_INVALID_SPENDER"
- );
-
- if (approvedAddress != address(0)) {
- approvals[_tokenId] = address(0);
- }
-
- owners[_tokenId] = _to;
- balances[_from] = safeSub(balances[_from], 1);
- balances[_to] = safeAdd(balances[_to], 1);
-
- emit Transfer(
- _from,
- _to,
- _tokenId
- );
- }
-
- /// @notice Find the owner of an NFT
- /// @dev NFTs assigned to zero address are considered invalid, and queries
- /// about them do throw.
- /// @param _tokenId The identifier for an NFT
- /// @return The address of the owner of the NFT
- function ownerOf(uint256 _tokenId)
- public
- view
- returns (address)
- {
- address owner = owners[_tokenId];
- require(
- owner != address(0),
- "ERC721_ZERO_OWNER"
- );
- return owner;
- }
-
- /// @notice Get the approved address for a single NFT
- /// @dev Throws if `_tokenId` is not a valid NFT.
- /// @param _tokenId The NFT to find the approved address for
- /// @return The approved address for this NFT, or the zero address if there is none
- function getApproved(uint256 _tokenId)
- public
- view
- returns (address)
- {
- return approvals[_tokenId];
- }
-
- /// @notice Query if an address is an authorized operator for another address
- /// @param _owner The address that owns the NFTs
- /// @param _operator The address that acts on behalf of the owner
- /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
- function isApprovedForAll(address _owner, address _operator)
- public
- view
- returns (bool)
- {
- return operatorApprovals[_owner][_operator];
- }
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol b/packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol
deleted file mode 100644
index 8e0e32ab2..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/IERC721Receiver.sol
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-
- 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;
-
-
-contract IERC721Receiver {
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes _data
- )
- external
- returns (bytes4);
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol b/packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol
deleted file mode 100644
index ac992c80d..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/IERC721Token.sol
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-
- 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;
-
-
-contract IERC721Token {
-
- /// @dev This emits when ownership of any NFT changes by any mechanism.
- /// This event emits when NFTs are created (`from` == 0) and destroyed
- /// (`to` == 0). Exception: during contract creation, any number of NFTs
- /// may be created and assigned without emitting Transfer. At the time of
- /// any transfer, the approved address for that NFT (if any) is reset to none.
- event Transfer(
- address indexed _from,
- address indexed _to,
- uint256 indexed _tokenId
- );
-
- /// @dev This emits when the approved address for an NFT is changed or
- /// reaffirmed. The zero address indicates there is no approved address.
- /// When a Transfer event emits, this also indicates that the approved
- /// address for that NFT (if any) is reset to none.
- event Approval(
- address indexed _owner,
- address indexed _approved,
- uint256 indexed _tokenId
- );
-
- /// @dev This emits when an operator is enabled or disabled for an owner.
- /// The operator can manage all NFTs of the owner.
- event ApprovalForAll(
- address indexed _owner,
- address indexed _operator,
- bool _approved
- );
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// perator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT. When transfer is complete, this function
- /// checks if `_to` is a smart contract (code size > 0). If so, it calls
- /// `onERC721Received` on `_to` and throws if the return value is not
- /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- /// @param _data Additional data with no specified format, sent in call to `_to`
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId,
- bytes _data
- )
- external;
-
- /// @notice Transfers the ownership of an NFT from one address to another address
- /// @dev This works identically to the other function with an extra data parameter,
- /// except this function just sets data to "".
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function safeTransferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- external;
-
- /// @notice Change or reaffirm the approved address for an NFT
- /// @dev The zero address indicates there is no approved address.
- /// Throws unless `msg.sender` is the current NFT owner, or an authorized
- /// operator of the current owner.
- /// @param _approved The new approved NFT controller
- /// @param _tokenId The NFT to approve
- function approve(address _approved, uint256 _tokenId)
- external;
-
- /// @notice Enable or disable approval for a third party ("operator") to manage
- /// all of `msg.sender`'s assets
- /// @dev Emits the ApprovalForAll event. The contract MUST allow
- /// multiple operators per owner.
- /// @param _operator Address to add to the set of authorized operators
- /// @param _approved True if the operator is approved, false to revoke approval
- function setApprovalForAll(address _operator, bool _approved)
- external;
-
- /// @notice Count all NFTs assigned to an owner
- /// @dev NFTs assigned to the zero address are considered invalid, and this
- /// function throws for queries about the zero address.
- /// @param _owner An address for whom to query the balance
- /// @return The number of NFTs owned by `_owner`, possibly zero
- function balanceOf(address _owner)
- external
- view
- returns (uint256);
-
- /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
- /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
- /// THEY MAY BE PERMANENTLY LOST
- /// @dev Throws unless `msg.sender` is the current owner, an authorized
- /// operator, or the approved address for this NFT. Throws if `_from` is
- /// not the current owner. Throws if `_to` is the zero address. Throws if
- /// `_tokenId` is not a valid NFT.
- /// @param _from The current owner of the NFT
- /// @param _to The new owner
- /// @param _tokenId The NFT to transfer
- function transferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- public;
-
- /// @notice Find the owner of an NFT
- /// @dev NFTs assigned to zero address are considered invalid, and queries
- /// about them do throw.
- /// @param _tokenId The identifier for an NFT
- /// @return The address of the owner of the NFT
- function ownerOf(uint256 _tokenId)
- public
- view
- returns (address);
-
- /// @notice Get the approved address for a single NFT
- /// @dev Throws if `_tokenId` is not a valid NFT.
- /// @param _tokenId The NFT to find the approved address for
- /// @return The approved address for this NFT, or the zero address if there is none
- function getApproved(uint256 _tokenId)
- public
- view
- returns (address);
-
- /// @notice Query if an address is an authorized operator for another address
- /// @param _owner The address that owns the NFTs
- /// @param _operator The address that acts on behalf of the owner
- /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
- function isApprovedForAll(address _owner, address _operator)
- public
- view
- returns (bool);
-}
diff --git a/packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol b/packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol
deleted file mode 100644
index bc5cd2cc2..000000000
--- a/packages/contracts/contracts/tokens/ERC721Token/MintableERC721Token.sol
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-
- 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 "./ERC721Token.sol";
-
-
-contract MintableERC721Token is
- ERC721Token
-{
- /// @dev Function to mint a new token
- /// Reverts if the given token ID already exists
- /// @param _to Address of the beneficiary that will own the minted token
- /// @param _tokenId ID of the token to be minted by the msg.sender
- function _mint(address _to, uint256 _tokenId)
- internal
- {
- require(
- _to != address(0),
- "ERC721_ZERO_TO_ADDRESS"
- );
-
- address owner = owners[_tokenId];
- require(
- owner == address(0),
- "ERC721_OWNER_ALREADY_EXISTS"
- );
-
- owners[_tokenId] = _to;
- balances[_to] = safeAdd(balances[_to], 1);
-
- emit Transfer(
- address(0),
- _to,
- _tokenId
- );
- }
-
- /// @dev Function to burn a token
- /// Reverts if the given token ID doesn't exist
- /// @param _owner Owner of token with given token ID
- /// @param _tokenId ID of the token to be burned by the msg.sender
- function _burn(address _owner, uint256 _tokenId)
- internal
- {
- require(
- _owner != address(0),
- "ERC721_ZERO_OWNER_ADDRESS"
- );
-
- address owner = owners[_tokenId];
- require(
- owner == _owner,
- "ERC721_OWNER_MISMATCH"
- );
-
- owners[_tokenId] = address(0);
- balances[_owner] = safeSub(balances[_owner], 1);
-
- emit Transfer(
- _owner,
- address(0),
- _tokenId
- );
- }
-}
diff --git a/packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol b/packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol
deleted file mode 100644
index 9e2e68766..000000000
--- a/packages/contracts/contracts/tokens/EtherToken/IEtherToken.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-
- 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 "../ERC20Token/IERC20Token.sol";
-
-
-contract IEtherToken is
- IERC20Token
-{
- function deposit()
- public
- payable;
-
- function withdraw(uint256 amount)
- public;
-}
diff --git a/packages/contracts/contracts/tokens/EtherToken/WETH9.sol b/packages/contracts/contracts/tokens/EtherToken/WETH9.sol
deleted file mode 100644
index 17876b86d..000000000
--- a/packages/contracts/contracts/tokens/EtherToken/WETH9.sol
+++ /dev/null
@@ -1,758 +0,0 @@
-// Copyright (C) 2015, 2016, 2017 Dapphub
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-// solhint-disable
-pragma solidity ^0.4.18;
-
-
-contract WETH9 {
- string public name = "Wrapped Ether";
- string public symbol = "WETH";
- uint8 public decimals = 18;
-
- event Approval(address indexed _owner, address indexed _spender, uint _value);
- event Transfer(address indexed _from, address indexed _to, uint _value);
- event Deposit(address indexed _owner, uint _value);
- event Withdrawal(address indexed _owner, uint _value);
-
- mapping (address => uint) public balanceOf;
- mapping (address => mapping (address => uint)) public allowance;
-
- function() public payable {
- deposit();
- }
- function deposit() public payable {
- balanceOf[msg.sender] += msg.value;
- Deposit(msg.sender, msg.value);
- }
- function withdraw(uint wad) public {
- require(balanceOf[msg.sender] >= wad);
- balanceOf[msg.sender] -= wad;
- msg.sender.transfer(wad);
- Withdrawal(msg.sender, wad);
- }
-
- function totalSupply() public view returns (uint) {
- return this.balance;
- }
-
- function approve(address guy, uint wad) public returns (bool) {
- allowance[msg.sender][guy] = wad;
- Approval(msg.sender, guy, wad);
- return true;
- }
-
- function transfer(address dst, uint wad) public returns (bool) {
- return transferFrom(msg.sender, dst, wad);
- }
-
- function transferFrom(address src, address dst, uint wad)
- public
- returns (bool)
- {
- require(balanceOf[src] >= wad);
-
- if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
- require(allowance[src][msg.sender] >= wad);
- allowance[src][msg.sender] -= wad;
- }
-
- balanceOf[src] -= wad;
- balanceOf[dst] += wad;
-
- Transfer(src, dst, wad);
-
- return true;
- }
-}
-
-
-/*
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
-*/
diff --git a/packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol b/packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol
deleted file mode 100644
index 4920c4aac..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/ERC20Token_v1.sol
+++ /dev/null
@@ -1,44 +0,0 @@
-pragma solidity ^0.4.11;
-
-import { Token_v1 as Token } from "./Token_v1.sol";
-
-contract ERC20Token_v1 is Token {
-
- function transfer(address _to, uint _value) returns (bool) {
- //Default assumes totalSupply can't be over max (2^256 - 1).
- if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
- balances[msg.sender] -= _value;
- balances[_to] += _value;
- Transfer(msg.sender, _to, _value);
- return true;
- } else { return false; }
- }
-
- function transferFrom(address _from, address _to, uint _value) returns (bool) {
- if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {
- balances[_to] += _value;
- balances[_from] -= _value;
- allowed[_from][msg.sender] -= _value;
- Transfer(_from, _to, _value);
- return true;
- } else { return false; }
- }
-
- function balanceOf(address _owner) constant returns (uint) {
- return balances[_owner];
- }
-
- function approve(address _spender, uint _value) returns (bool) {
- allowed[msg.sender][_spender] = _value;
- Approval(msg.sender, _spender, _value);
- return true;
- }
-
- function allowance(address _owner, address _spender) constant returns (uint) {
- return allowed[_owner][_spender];
- }
-
- mapping (address => uint) balances;
- mapping (address => mapping (address => uint)) allowed;
- uint public totalSupply;
-}
diff --git a/packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol b/packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol
deleted file mode 100644
index de619fb7e..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/Token_v1.sol
+++ /dev/null
@@ -1,39 +0,0 @@
-pragma solidity ^0.4.11;
-
-contract Token_v1 {
-
- /// @return total amount of tokens
- function totalSupply() constant returns (uint supply) {}
-
- /// @param _owner The address from which the balance will be retrieved
- /// @return The balance
- function balanceOf(address _owner) constant returns (uint balance) {}
-
- /// @notice send `_value` token to `_to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transfer(address _to, uint _value) returns (bool success) {}
-
- /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _value The amount of token to be transferred
- /// @return Whether the transfer was successful or not
- function transferFrom(address _from, address _to, uint _value) returns (bool success) {}
-
- /// @notice `msg.sender` approves `_addr` to spend `_value` tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _value The amount of wei to be approved for transfer
- /// @return Whether the approval was successful or not
- function approve(address _spender, uint _value) returns (bool success) {}
-
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens allowed to spent
- function allowance(address _owner, address _spender) constant returns (uint remaining) {}
-
- event Transfer(address indexed _from, address indexed _to, uint _value);
- event Approval(address indexed _owner, address indexed _spender, uint _value);
-}
-
diff --git a/packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol b/packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol
deleted file mode 100644
index bf1b0335a..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/UnlimitedAllowanceToken_v1.sol
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-
- 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.11;
-
-import { ERC20Token_v1 as ERC20Token } from "./ERC20Token_v1.sol";
-
-contract UnlimitedAllowanceToken_v1 is ERC20Token {
-
- uint constant MAX_UINT = 2**256 - 1;
-
- /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
- /// @param _from Address to transfer from.
- /// @param _to Address to transfer to.
- /// @param _value Amount to transfer.
- /// @return Success of transfer.
- function transferFrom(address _from, address _to, uint _value)
- public
- returns (bool)
- {
- uint allowance = allowed[_from][msg.sender];
- if (balances[_from] >= _value
- && allowance >= _value
- && balances[_to] + _value >= balances[_to]
- ) {
- balances[_to] += _value;
- balances[_from] -= _value;
- if (allowance < MAX_UINT) {
- allowed[_from][msg.sender] -= _value;
- }
- Transfer(_from, _to, _value);
- return true;
- } else {
- return false;
- }
- }
-}
diff --git a/packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol b/packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol
deleted file mode 100644
index 831e1822c..000000000
--- a/packages/contracts/contracts/tokens/ZRXToken/ZRXToken.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
- 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.11;
-
-// solhint-disable-next-line max-line-length
-import { UnlimitedAllowanceToken_v1 as UnlimitedAllowanceToken } from "./UnlimitedAllowanceToken_v1.sol";
-
-
-contract ZRXToken is
- UnlimitedAllowanceToken
-{
-
- // solhint-disable const-name-snakecase
- uint8 constant public decimals = 18;
- uint256 public totalSupply = 10**27; // 1 billion tokens, 18 decimal places
- string constant public name = "0x Protocol Token";
- string constant public symbol = "ZRX";
- // solhint-enableconst-name-snakecase
-
- function ZRXToken()
- public
- {
- balances[msg.sender] = totalSupply;
- }
-}
diff --git a/packages/contracts/contracts/utils/LibBytes/LibBytes.sol b/packages/contracts/contracts/utils/LibBytes/LibBytes.sol
deleted file mode 100644
index 369f588ad..000000000
--- a/packages/contracts/contracts/utils/LibBytes/LibBytes.sol
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
-
- 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;
-
-
-library LibBytes {
-
- using LibBytes for bytes;
-
- /// @dev Gets the memory address for a byte array.
- /// @param input Byte array to lookup.
- /// @return memoryAddress Memory address of byte array. This
- /// points to the header of the byte array which contains
- /// the length.
- function rawAddress(bytes memory input)
- internal
- pure
- returns (uint256 memoryAddress)
- {
- assembly {
- memoryAddress := input
- }
- return memoryAddress;
- }
-
- /// @dev Gets the memory address for the contents of a byte array.
- /// @param input Byte array to lookup.
- /// @return memoryAddress Memory address of the contents of the byte array.
- function contentAddress(bytes memory input)
- internal
- pure
- returns (uint256 memoryAddress)
- {
- assembly {
- memoryAddress := add(input, 32)
- }
- return memoryAddress;
- }
-
- /// @dev Copies `length` bytes from memory location `source` to `dest`.
- /// @param dest memory address to copy bytes to.
- /// @param source memory address to copy bytes from.
- /// @param length number of bytes to copy.
- function memCopy(
- uint256 dest,
- uint256 source,
- uint256 length
- )
- internal
- pure
- {
- if (length < 32) {
- // Handle a partial word by reading destination and masking
- // off the bits we are interested in.
- // This correctly handles overlap, zero lengths and source == dest
- assembly {
- let mask := sub(exp(256, sub(32, length)), 1)
- let s := and(mload(source), not(mask))
- let d := and(mload(dest), mask)
- mstore(dest, or(s, d))
- }
- } else {
- // Skip the O(length) loop when source == dest.
- if (source == dest) {
- return;
- }
-
- // For large copies we copy whole words at a time. The final
- // word is aligned to the end of the range (instead of after the
- // previous) to handle partial words. So a copy will look like this:
- //
- // ####
- // ####
- // ####
- // ####
- //
- // We handle overlap in the source and destination range by
- // changing the copying direction. This prevents us from
- // overwriting parts of source that we still need to copy.
- //
- // This correctly handles source == dest
- //
- if (source > dest) {
- assembly {
- // We subtract 32 from `sEnd` and `dEnd` because it
- // is easier to compare with in the loop, and these
- // are also the addresses we need for copying the
- // last bytes.
- length := sub(length, 32)
- let sEnd := add(source, length)
- let dEnd := add(dest, length)
-
- // Remember the last 32 bytes of source
- // This needs to be done here and not after the loop
- // because we may have overwritten the last bytes in
- // source already due to overlap.
- let last := mload(sEnd)
-
- // Copy whole words front to back
- // Note: the first check is always true,
- // this could have been a do-while loop.
- // solhint-disable-next-line no-empty-blocks
- for {} lt(source, sEnd) {} {
- mstore(dest, mload(source))
- source := add(source, 32)
- dest := add(dest, 32)
- }
-
- // Write the last 32 bytes
- mstore(dEnd, last)
- }
- } else {
- assembly {
- // We subtract 32 from `sEnd` and `dEnd` because those
- // are the starting points when copying a word at the end.
- length := sub(length, 32)
- let sEnd := add(source, length)
- let dEnd := add(dest, length)
-
- // Remember the first 32 bytes of source
- // This needs to be done here and not after the loop
- // because we may have overwritten the first bytes in
- // source already due to overlap.
- let first := mload(source)
-
- // Copy whole words back to front
- // We use a signed comparisson here to allow dEnd to become
- // negative (happens when source and dest < 32). Valid
- // addresses in local memory will never be larger than
- // 2**255, so they can be safely re-interpreted as signed.
- // Note: the first check is always true,
- // this could have been a do-while loop.
- // solhint-disable-next-line no-empty-blocks
- for {} slt(dest, dEnd) {} {
- mstore(dEnd, mload(sEnd))
- sEnd := sub(sEnd, 32)
- dEnd := sub(dEnd, 32)
- }
-
- // Write the first 32 bytes
- mstore(dest, first)
- }
- }
- }
- }
-
- /// @dev Returns a slices from a byte array.
- /// @param b The byte array to take a slice from.
- /// @param from The starting index for the slice (inclusive).
- /// @param to The final index for the slice (exclusive).
- /// @return result The slice containing bytes at indices [from, to)
- function slice(
- bytes memory b,
- uint256 from,
- uint256 to
- )
- internal
- pure
- returns (bytes memory result)
- {
- require(
- from <= to,
- "FROM_LESS_THAN_TO_REQUIRED"
- );
- require(
- to < b.length,
- "TO_LESS_THAN_LENGTH_REQUIRED"
- );
-
- // Create a new bytes structure and copy contents
- result = new bytes(to - from);
- memCopy(
- result.contentAddress(),
- b.contentAddress() + from,
- result.length
- );
- return result;
- }
-
- /// @dev Returns a slice from a byte array without preserving the input.
- /// @param b The byte array to take a slice from. Will be destroyed in the process.
- /// @param from The starting index for the slice (inclusive).
- /// @param to The final index for the slice (exclusive).
- /// @return result The slice containing bytes at indices [from, to)
- /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.
- function sliceDestructive(
- bytes memory b,
- uint256 from,
- uint256 to
- )
- internal
- pure
- returns (bytes memory result)
- {
- require(
- from <= to,
- "FROM_LESS_THAN_TO_REQUIRED"
- );
- require(
- to < b.length,
- "TO_LESS_THAN_LENGTH_REQUIRED"
- );
-
- // Create a new bytes structure around [from, to) in-place.
- assembly {
- result := add(b, from)
- mstore(result, sub(to, from))
- }
- return result;
- }
-
- /// @dev Pops the last byte off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The byte that was popped off.
- function popLastByte(bytes memory b)
- internal
- pure
- returns (bytes1 result)
- {
- require(
- b.length > 0,
- "GREATER_THAN_ZERO_LENGTH_REQUIRED"
- );
-
- // Store last byte.
- result = b[b.length - 1];
-
- assembly {
- // Decrement length of byte array.
- let newLen := sub(mload(b), 1)
- mstore(b, newLen)
- }
- return result;
- }
-
- /// @dev Pops the last 20 bytes off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The 20 byte address that was popped off.
- function popLast20Bytes(bytes memory b)
- internal
- pure
- returns (address result)
- {
- require(
- b.length >= 20,
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Store last 20 bytes.
- result = readAddress(b, b.length - 20);
-
- assembly {
- // Subtract 20 from byte array length.
- let newLen := sub(mload(b), 20)
- mstore(b, newLen)
- }
- return result;
- }
-
- /// @dev Tests equality of two byte arrays.
- /// @param lhs First byte array to compare.
- /// @param rhs Second byte array to compare.
- /// @return True if arrays are the same. False otherwise.
- function equals(
- bytes memory lhs,
- bytes memory rhs
- )
- internal
- pure
- returns (bool equal)
- {
- // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.
- // We early exit on unequal lengths, but keccak would also correctly
- // handle this.
- return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);
- }
-
- /// @dev Reads an address from a position in a byte array.
- /// @param b Byte array containing an address.
- /// @param index Index in byte array of address.
- /// @return address from byte array.
- function readAddress(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (address result)
- {
- require(
- b.length >= index + 20, // 20 is length of address
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Add offset to index:
- // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
- // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
- index += 20;
-
- // Read address from array memory
- assembly {
- // 1. Add index to address of bytes array
- // 2. Load 32-byte word from memory
- // 3. Apply 20-byte mask to obtain address
- result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)
- }
- return result;
- }
-
- /// @dev Writes an address into a specific position in a byte array.
- /// @param b Byte array to insert address into.
- /// @param index Index in byte array of address.
- /// @param input Address to put into byte array.
- function writeAddress(
- bytes memory b,
- uint256 index,
- address input
- )
- internal
- pure
- {
- require(
- b.length >= index + 20, // 20 is length of address
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Add offset to index:
- // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
- // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
- index += 20;
-
- // Store address into array memory
- assembly {
- // The address occupies 20 bytes and mstore stores 32 bytes.
- // First fetch the 32-byte word where we'll be storing the address, then
- // apply a mask so we have only the bytes in the word that the address will not occupy.
- // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.
-
- // 1. Add index to address of bytes array
- // 2. Load 32-byte word from memory
- // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address
- let neighbors := and(
- mload(add(b, index)),
- 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
- )
-
- // Make sure input address is clean.
- // (Solidity does not guarantee this)
- input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)
-
- // Store the neighbors and address into memory
- mstore(add(b, index), xor(input, neighbors))
- }
- }
-
- /// @dev Reads a bytes32 value from a position in a byte array.
- /// @param b Byte array containing a bytes32 value.
- /// @param index Index in byte array of bytes32 value.
- /// @return bytes32 value from byte array.
- function readBytes32(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes32 result)
- {
- require(
- b.length >= index + 32,
- "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 256 bit length parameter
- index += 32;
-
- // Read the bytes32 from array memory
- assembly {
- result := mload(add(b, index))
- }
- return result;
- }
-
- /// @dev Writes a bytes32 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes32 to put into byte array.
- function writeBytes32(
- bytes memory b,
- uint256 index,
- bytes32 input
- )
- internal
- pure
- {
- require(
- b.length >= index + 32,
- "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 256 bit length parameter
- index += 32;
-
- // Read the bytes32 from array memory
- assembly {
- mstore(add(b, index), input)
- }
- }
-
- /// @dev Reads a uint256 value from a position in a byte array.
- /// @param b Byte array containing a uint256 value.
- /// @param index Index in byte array of uint256 value.
- /// @return uint256 value from byte array.
- function readUint256(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (uint256 result)
- {
- result = uint256(readBytes32(b, index));
- return result;
- }
-
- /// @dev Writes a uint256 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input uint256 to put into byte array.
- function writeUint256(
- bytes memory b,
- uint256 index,
- uint256 input
- )
- internal
- pure
- {
- writeBytes32(b, index, bytes32(input));
- }
-
- /// @dev Reads an unpadded bytes4 value from a position in a byte array.
- /// @param b Byte array containing a bytes4 value.
- /// @param index Index in byte array of bytes4 value.
- /// @return bytes4 value from byte array.
- function readBytes4(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes4 result)
- {
- require(
- b.length >= index + 4,
- "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 32 byte length field
- index += 32;
-
- // Read the bytes4 from array memory
- assembly {
- result := mload(add(b, index))
- // Solidity does not require us to clean the trailing bytes.
- // We do it anyway
- result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
- }
- return result;
- }
-
- /// @dev Reads nested bytes from a specific position.
- /// @dev NOTE: the returned value overlaps with the input value.
- /// Both should be treated as immutable.
- /// @param b Byte array containing nested bytes.
- /// @param index Index of nested bytes.
- /// @return result Nested bytes.
- function readBytesWithLength(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes memory result)
- {
- // Read length of nested bytes
- uint256 nestedBytesLength = readUint256(b, index);
- index += 32;
-
- // Assert length of <b> is valid, given
- // length of nested bytes
- require(
- b.length >= index + nestedBytesLength,
- "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED"
- );
-
- // Return a pointer to the byte array as it exists inside `b`
- assembly {
- result := add(b, index)
- }
- return result;
- }
-
- /// @dev Inserts bytes at a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes to insert.
- function writeBytesWithLength(
- bytes memory b,
- uint256 index,
- bytes memory input
- )
- internal
- pure
- {
- // Assert length of <b> is valid, given
- // length of input
- require(
- b.length >= index + 32 + input.length, // 32 bytes to store length
- "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED"
- );
-
- // Copy <input> into <b>
- memCopy(
- b.contentAddress() + index,
- input.rawAddress(), // includes length of <input>
- input.length + 32 // +32 bytes to store <input> length
- );
- }
-
- /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
- /// @param dest Byte array that will be overwritten with source bytes.
- /// @param source Byte array to copy onto dest bytes.
- function deepCopyBytes(
- bytes memory dest,
- bytes memory source
- )
- internal
- pure
- {
- uint256 sourceLen = source.length;
- // Dest length must be >= source length, or some bytes would not be copied.
- require(
- dest.length >= sourceLen,
- "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED"
- );
- memCopy(
- dest.contentAddress(),
- source.contentAddress(),
- sourceLen
- );
- }
-}
diff --git a/packages/contracts/contracts/utils/Ownable/IOwnable.sol b/packages/contracts/contracts/utils/Ownable/IOwnable.sol
deleted file mode 100644
index 5deb13497..000000000
--- a/packages/contracts/contracts/utils/Ownable/IOwnable.sol
+++ /dev/null
@@ -1,8 +0,0 @@
-pragma solidity 0.4.24;
-
-
-contract IOwnable {
-
- function transferOwnership(address newOwner)
- public;
-}
diff --git a/packages/contracts/contracts/utils/Ownable/Ownable.sol b/packages/contracts/contracts/utils/Ownable/Ownable.sol
deleted file mode 100644
index 0c830be68..000000000
--- a/packages/contracts/contracts/utils/Ownable/Ownable.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-pragma solidity 0.4.24;
-
-import "./IOwnable.sol";
-
-
-contract Ownable is
- IOwnable
-{
- address public owner;
-
- constructor ()
- public
- {
- owner = msg.sender;
- }
-
- modifier onlyOwner() {
- require(
- msg.sender == owner,
- "ONLY_CONTRACT_OWNER"
- );
- _;
- }
-
- function transferOwnership(address newOwner)
- public
- onlyOwner
- {
- if (newOwner != address(0)) {
- owner = newOwner;
- }
- }
-}
diff --git a/packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol
deleted file mode 100644
index 9f98a7a16..000000000
--- a/packages/contracts/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-
- 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;
-
-
-contract ReentrancyGuard {
-
- // Locked state of mutex
- bool private locked = false;
-
- /// @dev Functions with this modifer cannot be reentered. The mutex will be locked
- /// before function execution and unlocked after.
- modifier nonReentrant() {
- // Ensure mutex is unlocked
- require(
- !locked,
- "REENTRANCY_ILLEGAL"
- );
-
- // Lock mutex before function call
- locked = true;
-
- // Perform function call
- _;
-
- // Unlock mutex after function call
- locked = false;
- }
-}
diff --git a/packages/contracts/contracts/utils/SafeMath/SafeMath.sol b/packages/contracts/contracts/utils/SafeMath/SafeMath.sol
deleted file mode 100644
index 2855edb9d..000000000
--- a/packages/contracts/contracts/utils/SafeMath/SafeMath.sol
+++ /dev/null
@@ -1,87 +0,0 @@
-pragma solidity 0.4.24;
-
-
-contract SafeMath {
-
- function safeMul(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- if (a == 0) {
- return 0;
- }
- uint256 c = a * b;
- require(
- c / a == b,
- "UINT256_OVERFLOW"
- );
- return c;
- }
-
- function safeDiv(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- uint256 c = a / b;
- return c;
- }
-
- function safeSub(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- require(
- b <= a,
- "UINT256_UNDERFLOW"
- );
- return a - b;
- }
-
- function safeAdd(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- uint256 c = a + b;
- require(
- c >= a,
- "UINT256_OVERFLOW"
- );
- return c;
- }
-
- function max64(uint64 a, uint64 b)
- internal
- pure
- returns (uint256)
- {
- return a >= b ? a : b;
- }
-
- function min64(uint64 a, uint64 b)
- internal
- pure
- returns (uint256)
- {
- return a < b ? a : b;
- }
-
- function max256(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- return a >= b ? a : b;
- }
-
- function min256(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- return a < b ? a : b;
- }
-}
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
deleted file mode 100644
index 25445c4f8..000000000
--- a/packages/contracts/package.json
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "private": true,
- "name": "contracts",
- "version": "2.1.55",
- "engines": {
- "node": ">=6.12"
- },
- "description": "Smart contract components of 0x protocol",
- "main": "lib/src/index.js",
- "directories": {
- "test": "test"
- },
- "scripts": {
- "build": "yarn pre_build && tsc -b",
- "build:ci": "yarn build",
- "pre_build": "run-s compile generate_contract_wrappers",
- "test": "yarn run_mocha",
- "rebuild_and_test": "run-s build test",
- "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",
- "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",
- "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
- "coverage:report:text": "istanbul report text",
- "coverage:report:html": "istanbul report html && open coverage/index.html",
- "profiler:report:html": "istanbul report html && open coverage/index.html",
- "coverage:report:lcov": "istanbul report lcov",
- "test:circleci": "yarn test",
- "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"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/0xProject/0x-monorepo.git"
- },
- "author": "Amir Bandeali",
- "license": "Apache-2.0",
- "bugs": {
- "url": "https://github.com/0xProject/0x-monorepo/issues"
- },
- "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
- "devDependencies": {
- "@0x/abi-gen": "^1.0.17",
- "@0x/dev-utils": "^1.0.18",
- "@0x/sol-compiler": "^1.1.13",
- "@0x/sol-cov": "^2.1.13",
- "@0x/subproviders": "^2.1.5",
- "@0x/tslint-config": "^1.0.10",
- "@types/bn.js": "^4.11.0",
- "@types/ethereumjs-abi": "^0.6.0",
- "@types/lodash": "4.14.104",
- "@types/node": "*",
- "@types/yargs": "^10.0.0",
- "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",
- "shx": "^0.2.2",
- "solc": "^0.4.24",
- "solhint": "^1.2.1",
- "tslint": "5.11.0",
- "typescript": "3.0.1",
- "yargs": "^10.0.3"
- },
- "dependencies": {
- "@0x/base-contract": "^3.0.7",
- "@0x/order-utils": "^3.0.3",
- "@0x/types": "^1.3.0",
- "@0x/typescript-typings": "^3.0.4",
- "@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
- "@types/js-combinatorics": "^0.5.29",
- "bn.js": "^4.11.8",
- "ethereum-types": "^1.1.2",
- "ethereumjs-abi": "0.6.5",
- "ethereumjs-util": "^5.1.1",
- "ethers": "~4.0.4",
- "js-combinatorics": "^0.5.3",
- "lodash": "^4.17.5"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/packages/contracts/src/artifacts/index.ts b/packages/contracts/src/artifacts/index.ts
deleted file mode 100644
index c30972a91..000000000
--- a/packages/contracts/src/artifacts/index.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { ContractArtifact } from 'ethereum-types';
-
-import * as AssetProxyOwner from '../../generated-artifacts/AssetProxyOwner.json';
-import * as DummyERC20Token from '../../generated-artifacts/DummyERC20Token.json';
-import * as DummyERC721Receiver from '../../generated-artifacts/DummyERC721Receiver.json';
-import * as DummyERC721Token from '../../generated-artifacts/DummyERC721Token.json';
-import * as DummyMultipleReturnERC20Token from '../../generated-artifacts/DummyMultipleReturnERC20Token.json';
-import * as DummyNoReturnERC20Token from '../../generated-artifacts/DummyNoReturnERC20Token.json';
-import * as ERC20Proxy from '../../generated-artifacts/ERC20Proxy.json';
-import * as ERC20Token from '../../generated-artifacts/ERC20Token.json';
-import * as ERC721Proxy from '../../generated-artifacts/ERC721Proxy.json';
-import * as ERC721Token from '../../generated-artifacts/ERC721Token.json';
-import * as Exchange from '../../generated-artifacts/Exchange.json';
-import * as ExchangeWrapper from '../../generated-artifacts/ExchangeWrapper.json';
-import * as Forwarder from '../../generated-artifacts/Forwarder.json';
-import * as IAssetData from '../../generated-artifacts/IAssetData.json';
-import * as IAssetProxy from '../../generated-artifacts/IAssetProxy.json';
-import * as InvalidERC721Receiver from '../../generated-artifacts/InvalidERC721Receiver.json';
-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 MultiSigWallet from '../../generated-artifacts/MultiSigWallet.json';
-import * as MultiSigWalletWithTimeLock from '../../generated-artifacts/MultiSigWalletWithTimeLock.json';
-import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
-import * as ReentrantERC20Token from '../../generated-artifacts/ReentrantERC20Token.json';
-import * as TestAssetProxyDispatcher from '../../generated-artifacts/TestAssetProxyDispatcher.json';
-import * as TestAssetProxyOwner from '../../generated-artifacts/TestAssetProxyOwner.json';
-import * as TestConstants from '../../generated-artifacts/TestConstants.json';
-import * as TestExchangeInternals from '../../generated-artifacts/TestExchangeInternals.json';
-import * as TestLibBytes from '../../generated-artifacts/TestLibBytes.json';
-import * as TestLibs from '../../generated-artifacts/TestLibs.json';
-import * as TestSignatureValidator from '../../generated-artifacts/TestSignatureValidator.json';
-import * as TestStaticCallReceiver from '../../generated-artifacts/TestStaticCallReceiver.json';
-import * as Validator from '../../generated-artifacts/Validator.json';
-import * as Wallet from '../../generated-artifacts/Wallet.json';
-import * as WETH9 from '../../generated-artifacts/WETH9.json';
-import * as Whitelist from '../../generated-artifacts/Whitelist.json';
-import * as ZRXToken from '../../generated-artifacts/ZRXToken.json';
-
-export const artifacts = {
- AssetProxyOwner: AssetProxyOwner as ContractArtifact,
- DummyERC20Token: DummyERC20Token as ContractArtifact,
- DummyERC721Receiver: DummyERC721Receiver as ContractArtifact,
- DummyERC721Token: DummyERC721Token as ContractArtifact,
- DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
- DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
- ERC20Proxy: ERC20Proxy as ContractArtifact,
- ERC20Token: ERC20Token as ContractArtifact,
- ERC721Proxy: ERC721Proxy as ContractArtifact,
- ERC721Token: ERC721Token as ContractArtifact,
- Exchange: Exchange as ContractArtifact,
- ExchangeWrapper: ExchangeWrapper as ContractArtifact,
- Forwarder: Forwarder as ContractArtifact,
- IAssetData: IAssetData as ContractArtifact,
- IAssetProxy: IAssetProxy as ContractArtifact,
- IValidator: IValidator as ContractArtifact,
- IWallet: IWallet as ContractArtifact,
- InvalidERC721Receiver: InvalidERC721Receiver as ContractArtifact,
- MixinAuthorizable: MixinAuthorizable as ContractArtifact,
- MultiSigWallet: MultiSigWallet as ContractArtifact,
- MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact,
- OrderValidator: OrderValidator as ContractArtifact,
- ReentrantERC20Token: ReentrantERC20Token as ContractArtifact,
- TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact,
- TestAssetProxyOwner: TestAssetProxyOwner as ContractArtifact,
- TestConstants: TestConstants as ContractArtifact,
- TestExchangeInternals: TestExchangeInternals as ContractArtifact,
- TestLibBytes: TestLibBytes as ContractArtifact,
- TestLibs: TestLibs as ContractArtifact,
- TestSignatureValidator: TestSignatureValidator as ContractArtifact,
- TestStaticCallReceiver: TestStaticCallReceiver as ContractArtifact,
- Validator: Validator as ContractArtifact,
- WETH9: WETH9 as ContractArtifact,
- Wallet: Wallet as ContractArtifact,
- Whitelist: Whitelist as ContractArtifact,
- // Note(albrow): "as any" hack still required here because ZRXToken does not
- // conform to the v2 artifact type.
- ZRXToken: (ZRXToken as any) as ContractArtifact,
-};
diff --git a/packages/contracts/src/wrappers/index.ts b/packages/contracts/src/wrappers/index.ts
deleted file mode 100644
index 9ca676b56..000000000
--- a/packages/contracts/src/wrappers/index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-export * from '../../generated-wrappers/asset_proxy_owner';
-export * from '../../generated-wrappers/dummy_erc20_token';
-export * from '../../generated-wrappers/dummy_erc721_receiver';
-export * from '../../generated-wrappers/dummy_erc721_token';
-export * from '../../generated-wrappers/dummy_multiple_return_erc20_token';
-export * from '../../generated-wrappers/dummy_no_return_erc20_token';
-export * from '../../generated-wrappers/erc20_proxy';
-export * from '../../generated-wrappers/erc721_proxy';
-export * from '../../generated-wrappers/erc20_token';
-export * from '../../generated-wrappers/erc721_token';
-export * from '../../generated-wrappers/exchange';
-export * from '../../generated-wrappers/exchange_wrapper';
-export * from '../../generated-wrappers/forwarder';
-export * from '../../generated-wrappers/i_asset_data';
-export * from '../../generated-wrappers/i_asset_proxy';
-export * from '../../generated-wrappers/invalid_erc721_receiver';
-export * from '../../generated-wrappers/mixin_authorizable';
-export * from '../../generated-wrappers/multi_sig_wallet';
-export * from '../../generated-wrappers/multi_sig_wallet_with_time_lock';
-export * from '../../generated-wrappers/order_validator';
-export * from '../../generated-wrappers/reentrant_erc20_token';
-export * from '../../generated-wrappers/test_asset_proxy_dispatcher';
-export * from '../../generated-wrappers/test_asset_proxy_owner';
-export * from '../../generated-wrappers/test_constants';
-export * from '../../generated-wrappers/test_exchange_internals';
-export * from '../../generated-wrappers/test_lib_bytes';
-export * from '../../generated-wrappers/test_libs';
-export * from '../../generated-wrappers/test_signature_validator';
-export * from '../../generated-wrappers/test_static_call_receiver';
-export * from '../../generated-wrappers/validator';
-export * from '../../generated-wrappers/wallet';
-export * from '../../generated-wrappers/weth9';
-export * from '../../generated-wrappers/whitelist';
-export * from '../../generated-wrappers/zrx_token';
diff --git a/packages/contracts/test/asset_proxy/authorizable.ts b/packages/contracts/test/asset_proxy/authorizable.ts
deleted file mode 100644
index e21af9b81..000000000
--- a/packages/contracts/test/asset_proxy/authorizable.ts
+++ /dev/null
@@ -1,207 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { MixinAuthorizableContract } from '../../generated-wrappers/mixin_authorizable';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Authorizable', () => {
- let owner: string;
- let notOwner: string;
- let address: string;
- let authorizable: MixinAuthorizableContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- [owner, address, notOwner] = _.slice(accounts, 0, 3);
- authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('addAuthorizedAddress', () => {
- it('should throw if not called by owner', async () => {
- return expectTransactionFailedAsync(
- authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
- RevertReason.OnlyContractOwner,
- );
- });
- it('should allow owner to add an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.true();
- });
- it('should throw if owner attempts to authorize a duplicate address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectTransactionFailedAsync(
- authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- RevertReason.TargetAlreadyAuthorized,
- );
- });
- });
-
- describe('removeAuthorizedAddress', () => {
- it('should throw if not called by owner', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: notOwner,
- }),
- RevertReason.OnlyContractOwner,
- );
- });
-
- it('should allow owner to remove an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.false();
- });
-
- it('should throw if owner attempts to remove an address that is not authorized', async () => {
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- RevertReason.TargetNotAuthorized,
- );
- });
- });
-
- describe('removeAuthorizedAddressAtIndex', () => {
- it('should throw if not called by owner', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: notOwner,
- }),
- RevertReason.OnlyContractOwner,
- );
- });
- it('should throw if index is >= authorities.length', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(1);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- RevertReason.IndexOutOfBounds,
- );
- });
- it('should throw if owner attempts to remove an address that is not authorized', async () => {
- const index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- RevertReason.TargetNotAuthorized,
- );
- });
- it('should throw if address at index does not match target', async () => {
- const address1 = address;
- const address2 = notOwner;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address1, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address2, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const address1Index = new BigNumber(0);
- return expectTransactionFailedAsync(
- authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
- from: owner,
- }),
- RevertReason.AuthorizedAddressMismatch,
- );
- });
- it('should allow owner to remove an authorized address', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const index = new BigNumber(0);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isAuthorized = await authorizable.authorized.callAsync(address);
- expect(isAuthorized).to.be.false();
- });
- });
-
- describe('getAuthorizedAddresses', () => {
- it('should return all authorized addresses', async () => {
- const initial = await authorizable.getAuthorizedAddresses.callAsync();
- expect(initial).to.have.length(0);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.addAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
- expect(afterAdd).to.have.length(1);
- expect(afterAdd).to.include(address);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
- expect(afterRemove).to.have.length(0);
- });
- });
-});
diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts
deleted file mode 100644
index b8305993e..000000000
--- a/packages/contracts/test/asset_proxy/proxies.ts
+++ /dev/null
@@ -1,629 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721ReceiverContract } from '../../generated-wrappers/dummy_erc721_receiver';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { DummyMultipleReturnERC20TokenContract } from '../../generated-wrappers/dummy_multiple_return_erc20_token';
-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 { IAssetProxyContract } from '../../generated-wrappers/i_asset_proxy';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { LogDecoder } from '../utils/log_decoder';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const assetProxyInterface = new IAssetProxyContract(
- artifacts.IAssetProxy.compilerOutput.abi,
- constants.NULL_ADDRESS,
- provider,
-);
-
-// tslint:disable:no-unnecessary-type-assertion
-describe('Asset Transfer Proxies', () => {
- let owner: string;
- let notAuthorized: string;
- let exchangeAddress: string;
- let makerAddress: string;
- let takerAddress: string;
-
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let erc721Receiver: DummyERC721ReceiverContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let noReturnErc20Token: DummyNoReturnERC20TokenContract;
- let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract;
-
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let erc721MakerTokenId: BigNumber;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, notAuthorized, exchangeAddress, makerAddress, takerAddress] = _.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);
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeAddress, {
- 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];
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeAddress, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Receiver,
- provider,
- txDefaults,
- );
- noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyNoReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.setBalance.sendTransactionAsync(makerAddress, constants.INITIAL_ERC20_BALANCE),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: makerAddress },
- ),
- 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,
- constants.INITIAL_ERC20_BALANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multipleReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('Transfer Proxy - ERC20', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: erc20Proxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- 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 erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- 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[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.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);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- 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));
- });
-
- 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 erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- 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[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.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 erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(0);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- 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[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address],
- );
- });
-
- it('should throw if allowances are too low', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.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,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- RevertReason.TransferFailed,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should throw 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.
- const allowance = new BigNumber(0);
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const initialMakerBalance = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialTakerBalance = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- 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);
- });
-
- it('should throw if requesting address is not authorized', async () => {
- // Construct ERC20 asset data
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(10);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should throw 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,
- amount,
- );
- const initialMakerBalance = await multipleReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialTakerBalance = await multipleReturnErc20Token.balanceOf.callAsync(takerAddress);
- // Perform a transfer; expect this to fail.
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc20Proxy.address,
- data,
- from: exchangeAddress,
- }),
- 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);
- });
- });
-
- 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', () => {
- it('should revert if undefined function is called', async () => {
- const undefinedSelector = '0x01020304';
- await expectTransactionFailedWithoutReasonAsync(
- web3Wrapper.sendTransactionAsync({
- from: owner,
- to: erc721Proxy.address,
- value: constants.ZERO_AMOUNT,
- data: undefinedSelector,
- }),
- );
- });
- describe('transferFrom', () => {
- it('should successfully transfer tokens', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
- // Verify pre-condition
- const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(ownerMakerAsset).to.be.equal(makerAddress);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: exchangeAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
- });
-
- it('should successfully transfer tokens and ignore extra assetData', async () => {
- // Construct ERC721 asset data
- const extraData = '0102030405060708';
- const encodedAssetData = `${assetDataUtils.encodeERC721AssetData(
- erc721Token.address,
- erc721MakerTokenId,
- )}${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 amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: exchangeAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Verify transfer was successful
- const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
- });
-
- it('should not call onERC721Received when transferring to a smart contract', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
- // Verify pre-condition
- const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(ownerMakerAsset).to.be.equal(makerAddress);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- erc721Receiver.address,
- amount,
- );
- const logDecoder = new LogDecoder(web3Wrapper);
- const tx = await logDecoder.getTxWithDecodedLogsAsync(
- await web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: exchangeAddress,
- 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);
- });
-
- it('should throw if transferring 0 amount of a token', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
- // Verify pre-condition
- const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(ownerMakerAsset).to.be.equal(makerAddress);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(0);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: exchangeAddress,
- }),
- RevertReason.InvalidAmount,
- );
- const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(newOwner).to.be.equal(ownerMakerAsset);
- });
-
- it('should throw if transferring > 1 amount of a token', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
- // Verify pre-condition
- const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(ownerMakerAsset).to.be.equal(makerAddress);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(500);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: exchangeAddress,
- }),
- RevertReason.InvalidAmount,
- );
- const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(newOwner).to.be.equal(ownerMakerAsset);
- });
-
- it('should throw if allowances are too low', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
- // Verify pre-condition
- const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(ownerMakerAsset).to.be.equal(makerAddress);
- // Remove transfer approval for makerAddress.
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.approve.sendTransactionAsync(constants.NULL_ADDRESS, erc721MakerTokenId, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Perform a transfer; expect this to fail.
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: exchangeAddress,
- }),
- RevertReason.TransferFailed,
- );
- const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(newOwner).to.be.equal(ownerMakerAsset);
- });
-
- it('should throw if requesting address is not authorized', async () => {
- // Construct ERC721 asset data
- const encodedAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
- // Verify pre-condition
- const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(ownerMakerAsset).to.be.equal(makerAddress);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(1);
- const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- );
- await expectTransactionFailedAsync(
- web3Wrapper.sendTransactionAsync({
- to: erc721Proxy.address,
- data,
- from: notAuthorized,
- }),
- RevertReason.SenderNotAuthorized,
- );
- const newOwner = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
- expect(newOwner).to.be.equal(ownerMakerAsset);
- });
- });
-
- it('should have an id of 0x02571792', async () => {
- const proxyId = await erc721Proxy.getProxyId.callAsync();
- const expectedProxyId = '0x02571792';
- expect(proxyId).to.equal(expectedProxyId);
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
-// tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts
deleted file mode 100644
index fc8dc5346..000000000
--- a/packages/contracts/test/exchange/core.ts
+++ /dev/null
@@ -1,829 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import ethUtil = require('ethereumjs-util');
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract, DummyERC20TokenTransferEventArgs } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-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 { ExchangeCancelEventArgs, ExchangeContract } from '../../generated-wrappers/exchange';
-import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
-import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_static_call_receiver';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { ERC20BalancesByOwner, OrderStatus } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('Exchange core', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let noReturnErc20Token: DummyNoReturnERC20TokenContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let maliciousWallet: TestStaticCallReceiverContract;
- let maliciousValidator: TestStaticCallReceiverContract;
-
- let signedOrder: SignedOrder;
- let erc20Balances: ERC20BalancesByOwner;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let orderFactory: OrderFactory;
-
- let erc721MakerAssetIds: BigNumber[];
- let erc721TakerAssetIds: BigNumber[];
-
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- 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);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
- artifacts.TestStaticCallReceiver,
- provider,
- txDefaults,
- );
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrder to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('fillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should throw if signature is invalid', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
-
- const v = ethUtil.toBuffer(signedOrder.signature.slice(0, 4));
- const invalidR = ethUtil.sha3('invalidR');
- const invalidS = ethUtil.sha3('invalidS');
- const signatureType = ethUtil.toBuffer(`0x${signedOrder.signature.slice(-2)}`);
- const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
- const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
- signedOrder.signature = invalidSigHex;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should throw if no value is filled', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should revert if `isValidSignature` tries to update state when SignatureType=Wallet', async () => {
- const maliciousMakerAddress = maliciousWallet.address;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.setBalance.sendTransactionAsync(
- maliciousMakerAddress,
- constants.INITIAL_ERC20_BALANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await maliciousWallet.approveERC20.sendTransactionAsync(
- erc20TokenA.address,
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAddress: maliciousMakerAddress,
- makerFee: constants.ZERO_AMOUNT,
- });
- signedOrder.signature = `0x0${SignatureType.Wallet}`;
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.WalletError,
- );
- });
-
- it('should revert if `isValidSignature` tries to update state when SignatureType=Validator', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await exchange.setSignatureValidatorApproval.sendTransactionAsync(
- maliciousValidator.address,
- isApproved,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- signedOrder.signature = `${maliciousValidator.address}0${SignatureType.Validator}`;
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
- RevertReason.ValidatorError,
- );
- });
-
- it('should not emit transfer events for transfers where from == to', async () => {
- const txReceipt = await exchangeWrapper.fillOrderAsync(signedOrder, makerAddress);
- const logs = txReceipt.logs;
- const transferLogs = _.filter(
- logs,
- log => (log as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).event === 'Transfer',
- );
- expect(transferLogs.length).to.be.equal(2);
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).address).to.be.equal(
- zrxToken.address,
- );
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._from).to.be.equal(
- makerAddress,
- );
- expect((transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._to).to.be.equal(
- feeRecipientAddress,
- );
- expect(
- (transferLogs[0] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
- ).to.be.bignumber.equal(signedOrder.makerFee);
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).address).to.be.equal(
- zrxToken.address,
- );
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._from).to.be.equal(
- makerAddress,
- );
- expect((transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._to).to.be.equal(
- feeRecipientAddress,
- );
- expect(
- (transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
- ).to.be.bignumber.equal(signedOrder.takerFee);
- });
- });
-
- describe('Testing exchange of ERC20 tokens with no return values', () => {
- before(async () => {
- noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyNoReturnERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.setBalance.sendTransactionAsync(makerAddress, constants.INITIAL_ERC20_BALANCE),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await noReturnErc20Token.approve.sendTransactionAsync(
- erc20Proxy.address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: makerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(noReturnErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
-
- const initialMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const initialMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const initialMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const initialTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const initialTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const initialTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const initialFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
-
- const finalMakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(makerAddress);
- const finalMakerBalanceB = await erc20TokenB.balanceOf.callAsync(makerAddress);
- const finalMakerZrxBalance = await zrxToken.balanceOf.callAsync(makerAddress);
- const finalTakerBalanceA = await noReturnErc20Token.balanceOf.callAsync(takerAddress);
- const finalTakerBalanceB = await erc20TokenB.balanceOf.callAsync(takerAddress);
- const finalTakerZrxBalance = await zrxToken.balanceOf.callAsync(takerAddress);
- const finalFeeRecipientZrxBalance = await zrxToken.balanceOf.callAsync(feeRecipientAddress);
-
- expect(finalMakerBalanceA).to.be.bignumber.equal(initialMakerBalanceA.minus(signedOrder.makerAssetAmount));
- expect(finalMakerBalanceB).to.be.bignumber.equal(initialMakerBalanceB.plus(signedOrder.takerAssetAmount));
- expect(finalTakerBalanceA).to.be.bignumber.equal(initialTakerBalanceA.plus(signedOrder.makerAssetAmount));
- expect(finalTakerBalanceB).to.be.bignumber.equal(initialTakerBalanceB.minus(signedOrder.takerAssetAmount));
- expect(finalMakerZrxBalance).to.be.bignumber.equal(initialMakerZrxBalance.minus(signedOrder.makerFee));
- expect(finalTakerZrxBalance).to.be.bignumber.equal(initialTakerZrxBalance.minus(signedOrder.takerFee));
- expect(finalFeeRecipientZrxBalance).to.be.bignumber.equal(
- initialFeeRecipientZrxBalance.plus(signedOrder.makerFee.plus(signedOrder.takerFee)),
- );
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- it('should throw if not sent by maker', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress),
- RevertReason.InvalidMaker,
- );
- });
-
- it('should throw if makerAssetAmount is 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(0),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if takerAssetAmount is 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(0),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should be able to cancel a full order', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
- }),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should log 1 event with correct arguments', async () => {
- const res = await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- expect(res.logs).to.have.length(1);
-
- const log = res.logs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>;
- const logArgs = log.args;
-
- expect(signedOrder.makerAddress).to.be.equal(logArgs.makerAddress);
- expect(signedOrder.makerAddress).to.be.equal(logArgs.senderAddress);
- expect(signedOrder.feeRecipientAddress).to.be.equal(logArgs.feeRecipientAddress);
- expect(signedOrder.makerAssetData).to.be.equal(logArgs.makerAssetData);
- expect(signedOrder.takerAssetData).to.be.equal(logArgs.takerAssetData);
- expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(logArgs.orderHash);
- });
-
- it('should throw if already cancelled', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if order is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).sub(10),
- });
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if rounding error is greater than 0.1%', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1001),
- takerAssetAmount: new BigNumber(3),
- });
-
- const fillTakerAssetAmount1 = new BigNumber(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: fillTakerAssetAmount1,
- });
-
- const fillTakerAssetAmount2 = new BigNumber(1);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: fillTakerAssetAmount2,
- }),
- RevertReason.RoundingError,
- );
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- it('should fail to set orderEpoch less than current orderEpoch', async () => {
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- const lesserOrderEpoch = new BigNumber(0);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrdersUpToAsync(lesserOrderEpoch, makerAddress),
- RevertReason.InvalidNewOrderEpoch,
- );
- });
-
- it('should fail to set orderEpoch equal to existing orderEpoch', async () => {
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress),
- RevertReason.InvalidNewOrderEpoch,
- );
- });
-
- it('should cancel only orders with a orderEpoch less than existing orderEpoch', async () => {
- // Cancel all transactions with a orderEpoch less than 1
- const orderEpoch = new BigNumber(1);
- await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
-
- // Create 3 orders with orderEpoch values: 0,1,2,3
- // Since we cancelled with orderEpoch=1, orders with orderEpoch<=1 will not be processed
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- const signedOrders = [
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 18),
- salt: new BigNumber(0),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(79), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(79), 18),
- salt: new BigNumber(1),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(979), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(979), 18),
- salt: new BigNumber(2),
- }),
- await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(7979), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(7979), 18),
- salt: new BigNumber(3),
- }),
- ];
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.add(signedOrders[3].makerAssetAmount);
- const fillTakerAssetAmount = signedOrders[2].takerAssetAmount.add(signedOrders[3].takerAssetAmount);
- const makerFee = signedOrders[2].makerFee.add(signedOrders[3].makerFee);
- const takerFee = signedOrders[2].takerFee.add(signedOrders[3].takerFee);
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(fillMakerAssetAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(fillTakerAssetAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(fillTakerAssetAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(fillMakerAssetAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
- });
-
- describe('Testing Exchange of ERC721 Tokens', () => {
- it('should throw when maker does not own the token with id makerAssetId', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721TakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[1];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.not.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.TransferFailed,
- );
- });
-
- it('should throw when taker does not own the token with id takerAssetId', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721MakerAssetIds[1];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.TransferFailed,
- );
- });
-
- it('should throw when makerAssetAmount is greater than 1', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(2),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.InvalidAmount,
- );
- });
-
- it('should throw when takerAssetAmount is greater than 1', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- const takerAssetId = erc721TakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(500),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.InvalidAmount,
- );
- });
-
- it('should throw on partial fill', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetIds[0];
- signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- });
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
- RevertReason.RoundingError,
- );
- });
- });
-
- describe('getOrderInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should return the correct orderInfo for an unfilled valid order', async () => {
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.FILLABLE;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a fully filled order', async () => {
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- const expectedOrderStatus = OrderStatus.FULLY_FILLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.FILLABLE;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a cancelled and unfilled order', async () => {
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.CANCELLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for a cancelled and partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.CANCELLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and unfilled order', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.EXPIRED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and partially filled order', async () => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = takerAssetFillAmount;
- const expectedOrderStatus = OrderStatus.EXPIRED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an expired and fully filled order', async () => {
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- // FULLY_FILLED takes precedence over EXPIRED
- const expectedOrderStatus = OrderStatus.FULLY_FILLED;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an order with a makerAssetAmount of 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: new BigNumber(0) });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.INVALID_MAKER_ASSET_AMOUNT;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- it('should return the correct orderInfo for an order with a takerAssetAmount of 0', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync({ takerAssetAmount: new BigNumber(0) });
- const orderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrder);
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.INVALID_TAKER_ASSET_AMOUNT;
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/exchange/dispatcher.ts b/packages/contracts/test/exchange/dispatcher.ts
deleted file mode 100644
index 3d3aa42c2..000000000
--- a/packages/contracts/test/exchange/dispatcher.ts
+++ /dev/null
@@ -1,280 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId, RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import {
- TestAssetProxyDispatcherAssetProxyRegisteredEventArgs,
- TestAssetProxyDispatcherContract,
-} from '../../generated-wrappers/test_asset_proxy_dispatcher';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { LogDecoder } from '../utils/log_decoder';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('AssetProxyDispatcher', () => {
- let owner: string;
- let notOwner: string;
- let makerAddress: string;
- let takerAddress: string;
-
- let zrxToken: DummyERC20TokenContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let assetProxyDispatcher: TestAssetProxyDispatcherContract;
-
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Setup accounts & addresses
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, notOwner, makerAddress, takerAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 1;
- [zrxToken] = await erc20Wrapper.deployDummyTokensAsync(numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS);
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
-
- assetProxyDispatcher = await TestAssetProxyDispatcherContract.deployFrom0xArtifactAsync(
- artifacts.TestAssetProxyDispatcher,
- provider,
- txDefaults,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(assetProxyDispatcher.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(assetProxyDispatcher.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('registerAssetProxy', () => {
- it('should record proxy upon registration', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- });
-
- it('should be able to record multiple proxies', async () => {
- // Record first proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- let proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- // Record another proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC721);
- expect(proxyAddress).to.be.equal(erc721Proxy.address);
- });
-
- it('should throw if a proxy with the same id is already registered', async () => {
- // Initial registration
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- // Deploy a new version of the ERC20 Transfer Proxy contract
- const newErc20TransferProxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC20Proxy,
- provider,
- txDefaults,
- );
- // Register new ERC20 Transfer Proxy contract
- return expectTransactionFailedAsync(
- assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, {
- from: owner,
- }),
- RevertReason.AssetProxyAlreadyExists,
- );
- });
-
- it('should throw if requesting address is not owner', async () => {
- return expectTransactionFailedAsync(
- assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: notOwner }),
- RevertReason.OnlyContractOwner,
- );
- });
-
- it('should log an event with correct arguments when an asset proxy is registered', async () => {
- const logDecoder = new LogDecoder(web3Wrapper);
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- );
- const logs = txReceipt.logs;
- const log = logs[0] as LogWithDecodedArgs<TestAssetProxyDispatcherAssetProxyRegisteredEventArgs>;
- expect(log.args.id).to.equal(AssetProxyId.ERC20);
- expect(log.args.assetProxy).to.equal(erc20Proxy.address);
- });
- });
-
- describe('getAssetProxy', () => {
- it('should return correct address of registered proxy', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(erc20Proxy.address);
- });
-
- it('should return NULL address if requesting non-existent proxy', async () => {
- const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
- expect(proxyAddress).to.be.equal(constants.NULL_ADDRESS);
- });
- });
-
- describe('dispatchTransferFrom', () => {
- it('should dispatch transfer to registered proxy', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- 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[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].add(amount),
- );
- });
-
- it('should not dispatch a transfer if amount == 0', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = constants.ZERO_AMOUNT;
- const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- expect(txReceipt.logs.length).to.be.equal(0);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should not dispatch a transfer if from == to', async () => {
- // Register ERC20 proxy
- await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- // Perform a transfer from makerAddress to takerAddress
- const erc20Balances = await erc20Wrapper.getBalancesAsync();
- const amount = new BigNumber(10);
- const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
- await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- makerAddress,
- amount,
- { from: owner },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- expect(txReceipt.logs.length).to.be.equal(0);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.deep.equal(erc20Balances);
- });
-
- it('should throw if dispatching to unregistered proxy', async () => {
- // Construct metadata for ERC20 proxy
- const encodedAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- // Perform a transfer from makerAddress to takerAddress
- const amount = new BigNumber(10);
- return expectTransactionFailedAsync(
- assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
- encodedAssetData,
- makerAddress,
- takerAddress,
- amount,
- { from: owner },
- ),
- RevertReason.AssetProxyDoesNotExist,
- );
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/exchange/fill_order.ts b/packages/contracts/test/exchange/fill_order.ts
deleted file mode 100644
index 37efaad2b..000000000
--- a/packages/contracts/test/exchange/fill_order.ts
+++ /dev/null
@@ -1,312 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import * as _ from 'lodash';
-
-import { chaiSetup } from '../utils/chai_setup';
-import {
- FillOrderCombinatorialUtils,
- fillOrderCombinatorialUtilsFactoryAsync,
-} from '../utils/fill_order_combinatorial_utils';
-import {
- AllowanceAmountScenario,
- AssetDataScenario,
- BalanceAmountScenario,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- FillScenario,
- OrderAssetAmountScenario,
- TakerAssetFillAmountScenario,
- TakerScenario,
-} from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const defaultFillScenario = {
- orderScenario: {
- takerScenario: TakerScenario.Unspecified,
- feeRecipientScenario: FeeRecipientAddressScenario.EthUserAddress,
- makerAssetAmountScenario: OrderAssetAmountScenario.Large,
- takerAssetAmountScenario: OrderAssetAmountScenario.Large,
- makerFeeScenario: OrderAssetAmountScenario.Large,
- takerFeeScenario: OrderAssetAmountScenario.Large,
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InFuture,
- makerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
- },
- takerStateScenario: {
- traderAssetBalance: BalanceAmountScenario.Higher,
- traderAssetAllowance: AllowanceAmountScenario.Higher,
- zrxFeeBalance: BalanceAmountScenario.Higher,
- zrxFeeAllowance: AllowanceAmountScenario.Higher,
- },
-};
-
-describe('FillOrder Tests', () => {
- let fillOrderCombinatorialUtils: FillOrderCombinatorialUtils;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- fillOrderCombinatorialUtils = await fillOrderCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults);
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrder', () => {
- const test = (fillScenarios: FillScenario[]) => {
- _.forEach(fillScenarios, fillScenario => {
- const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
- it(description, async () => {
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
- };
-
- const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations();
- describe('Combinatorially generated fills orders', () => test(allFillScenarios));
-
- it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerAssetAmountScenario: OrderAssetAmountScenario.Small,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Small,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount with zero decimals', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Small,
- makerAssetDataScenario: AssetDataScenario.ERC20ZeroDecimals,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerScenario: TakerScenario.CorrectlySpecified,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- it('should throw when taker is specified and order is claimed by other', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerScenario: TakerScenario.IncorrectlySpecified,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if makerAssetAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetAmountScenario: OrderAssetAmountScenario.Zero,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if takerAssetAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- takerAssetAmountScenario: OrderAssetAmountScenario.Zero,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if takerAssetFillAmount is 0', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if an order is expired', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if maker erc20Balances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetBalance: BalanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if taker erc20Balances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetBalance: BalanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if maker allowances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should throw if taker allowances are too low to fill order', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- takerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.TooLow,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
-
- describe('Testing exchange of ERC721 Tokens', () => {
- it('should successfully exchange a single token between the maker and taker (via fillOrder)', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario, true);
- });
-
- it('should successfully fill order when makerAsset is ERC20 and takerAsset is ERC721', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset is ERC721 and approveAll is set for it', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC20NonZRXEighteenDecimals,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
-
- it('should successfully fill order when makerAsset and takerAsset are ERC721 and approveAll is set for them', async () => {
- const fillScenario = {
- ...defaultFillScenario,
- orderScenario: {
- ...defaultFillScenario.orderScenario,
- makerAssetDataScenario: AssetDataScenario.ERC721,
- takerAssetDataScenario: AssetDataScenario.ERC721,
- },
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- makerStateScenario: {
- ...defaultFillScenario.makerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- takerStateScenario: {
- ...defaultFillScenario.takerStateScenario,
- traderAssetAllowance: AllowanceAmountScenario.Unlimited,
- },
- };
- await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
- });
- });
-});
diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts
deleted file mode 100644
index 109be29c6..000000000
--- a/packages/contracts/test/exchange/internal.ts
+++ /dev/null
@@ -1,466 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { Order, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals';
-import { artifacts } from '../../src/artifacts';
-import { getRevertReasonOrErrorMessageForSendTransactionAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { bytes32Values, testCombinatoriallyWithReferenceFuncAsync, uint256Values } from '../utils/combinatorial_utils';
-import { constants } from '../utils/constants';
-import { FillResults } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
-
-const emptyOrder: Order = {
- senderAddress: constants.NULL_ADDRESS,
- makerAddress: constants.NULL_ADDRESS,
- takerAddress: constants.NULL_ADDRESS,
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- makerAssetAmount: new BigNumber(0),
- takerAssetAmount: new BigNumber(0),
- makerAssetData: '0x',
- takerAssetData: '0x',
- salt: new BigNumber(0),
- exchangeAddress: constants.NULL_ADDRESS,
- feeRecipientAddress: constants.NULL_ADDRESS,
- expirationTimeSeconds: new BigNumber(0),
-};
-
-const emptySignedOrder: SignedOrder = {
- ...emptyOrder,
- signature: '',
-};
-
-const overflowErrorForCall = new Error(RevertReason.Uint256Overflow);
-
-describe('Exchange core internal functions', () => {
- let testExchange: TestExchangeInternalsContract;
- let overflowErrorForSendTransaction: Error | undefined;
- let divisionByZeroErrorForCall: Error | undefined;
- let roundingErrorForCall: Error | undefined;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
- artifacts.TestExchangeInternals,
- provider,
- txDefaults,
- );
- overflowErrorForSendTransaction = new Error(
- await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow),
- );
- divisionByZeroErrorForCall = new Error(RevertReason.DivisionByZero);
- roundingErrorForCall = new Error(RevertReason.RoundingError);
- });
- // Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
- // the blockchain state for any tests which modify it!
-
- async function referenceIsRoundingErrorFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- if (numerator.eq(0)) {
- return false;
- }
- if (target.eq(0)) {
- return false;
- }
- const product = numerator.mul(target);
- const remainder = product.mod(denominator);
- const remainderTimes1000 = remainder.mul('1000');
- const isError = remainderTimes1000.gte(product);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (remainderTimes1000.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return isError;
- }
-
- async function referenceIsRoundingErrorCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- if (numerator.eq(0)) {
- return false;
- }
- if (target.eq(0)) {
- return false;
- }
- const product = numerator.mul(target);
- const remainder = product.mod(denominator);
- const error = denominator.sub(remainder).mod(denominator);
- const errorTimes1000 = error.mul('1000');
- const isError = errorTimes1000.gte(product);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- if (errorTimes1000.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return isError;
- }
-
- async function referenceSafeGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const isRoundingError = await referenceIsRoundingErrorFloorAsync(numerator, denominator, target);
- if (isRoundingError) {
- throw roundingErrorForCall;
- }
- const product = numerator.mul(target);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return product.dividedToIntegerBy(denominator);
- }
-
- describe('addFillResults', async () => {
- function makeFillResults(value: BigNumber): FillResults {
- return {
- makerAssetFilledAmount: value,
- takerAssetFilledAmount: value,
- makerFeePaid: value,
- takerFeePaid: value,
- };
- }
- async function referenceAddFillResultsAsync(
- totalValue: BigNumber,
- singleValue: BigNumber,
- ): Promise<FillResults> {
- // Note(albrow): Here, each of totalFillResults and
- // singleFillResults will consist of fields with the same values.
- // This should be safe because none of the fields in a given
- // FillResults are ever used together in a mathemetical operation.
- // They are only used with the corresponding field from *the other*
- // FillResults, which are different.
- const totalFillResults = makeFillResults(totalValue);
- const singleFillResults = makeFillResults(singleValue);
- // HACK(albrow): _.mergeWith mutates the first argument! To
- // workaround this we use _.cloneDeep.
- return _.mergeWith(
- _.cloneDeep(totalFillResults),
- singleFillResults,
- (totalVal: BigNumber, singleVal: BigNumber) => {
- const newTotal = totalVal.add(singleVal);
- if (newTotal.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return newTotal;
- },
- );
- }
- async function testAddFillResultsAsync(totalValue: BigNumber, singleValue: BigNumber): Promise<FillResults> {
- const totalFillResults = makeFillResults(totalValue);
- const singleFillResults = makeFillResults(singleValue);
- return testExchange.publicAddFillResults.callAsync(totalFillResults, singleFillResults);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'addFillResults',
- referenceAddFillResultsAsync,
- testAddFillResultsAsync,
- [uint256Values, uint256Values],
- );
- });
-
- describe('calculateFillResults', async () => {
- function makeOrder(
- makerAssetAmount: BigNumber,
- takerAssetAmount: BigNumber,
- makerFee: BigNumber,
- takerFee: BigNumber,
- ): Order {
- return {
- ...emptyOrder,
- makerAssetAmount,
- takerAssetAmount,
- makerFee,
- takerFee,
- };
- }
- async function referenceCalculateFillResultsAsync(
- orderTakerAssetAmount: BigNumber,
- takerAssetFilledAmount: BigNumber,
- otherAmount: BigNumber,
- ): Promise<FillResults> {
- // Note(albrow): Here we are re-using the same value (otherAmount)
- // for order.makerAssetAmount, order.makerFee, and order.takerFee.
- // This should be safe because they are never used with each other
- // in any mathematical operation in either the reference TypeScript
- // implementation or the Solidity implementation of
- // calculateFillResults.
- const makerAssetFilledAmount = await referenceSafeGetPartialAmountFloorAsync(
- takerAssetFilledAmount,
- orderTakerAssetAmount,
- otherAmount,
- );
- const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
- const orderMakerAssetAmount = order.makerAssetAmount;
- return {
- makerAssetFilledAmount,
- takerAssetFilledAmount,
- makerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
- makerAssetFilledAmount,
- orderMakerAssetAmount,
- otherAmount,
- ),
- takerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
- takerAssetFilledAmount,
- orderTakerAssetAmount,
- otherAmount,
- ),
- };
- }
- async function testCalculateFillResultsAsync(
- orderTakerAssetAmount: BigNumber,
- takerAssetFilledAmount: BigNumber,
- otherAmount: BigNumber,
- ): Promise<FillResults> {
- const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
- return testExchange.publicCalculateFillResults.callAsync(order, takerAssetFilledAmount);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'calculateFillResults',
- referenceCalculateFillResultsAsync,
- testCalculateFillResultsAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('getPartialAmountFloor', async () => {
- async function referenceGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const product = numerator.mul(target);
- if (product.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- return product.dividedToIntegerBy(denominator);
- }
- async function testGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicGetPartialAmountFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'getPartialAmountFloor',
- referenceGetPartialAmountFloorAsync,
- testGetPartialAmountFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('getPartialAmountCeil', async () => {
- async function referenceGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const product = numerator.mul(target);
- const offset = product.add(denominator.sub(1));
- if (offset.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.mul(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.mul(denominator)).to.be.bignumber.gt(product);
- }
- return result;
- }
- async function testGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicGetPartialAmountCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'getPartialAmountCeil',
- referenceGetPartialAmountCeilAsync,
- testGetPartialAmountCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('safeGetPartialAmountFloor', async () => {
- async function testSafeGetPartialAmountFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicSafeGetPartialAmountFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'safeGetPartialAmountFloor',
- referenceSafeGetPartialAmountFloorAsync,
- testSafeGetPartialAmountFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('safeGetPartialAmountCeil', async () => {
- async function referenceSafeGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- if (denominator.eq(0)) {
- throw divisionByZeroErrorForCall;
- }
- const isRoundingError = await referenceIsRoundingErrorCeilAsync(numerator, denominator, target);
- if (isRoundingError) {
- throw roundingErrorForCall;
- }
- const product = numerator.mul(target);
- const offset = product.add(denominator.sub(1));
- if (offset.greaterThan(MAX_UINT256)) {
- throw overflowErrorForCall;
- }
- const result = offset.dividedToIntegerBy(denominator);
- if (product.mod(denominator).eq(0)) {
- expect(result.mul(denominator)).to.be.bignumber.eq(product);
- } else {
- expect(result.mul(denominator)).to.be.bignumber.gt(product);
- }
- return result;
- }
- async function testSafeGetPartialAmountCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<BigNumber> {
- return testExchange.publicSafeGetPartialAmountCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'safeGetPartialAmountCeil',
- referenceSafeGetPartialAmountCeilAsync,
- testSafeGetPartialAmountCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('isRoundingErrorFloor', async () => {
- async function testIsRoundingErrorFloorAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- return testExchange.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'isRoundingErrorFloor',
- referenceIsRoundingErrorFloorAsync,
- testIsRoundingErrorFloorAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('isRoundingErrorCeil', async () => {
- async function testIsRoundingErrorCeilAsync(
- numerator: BigNumber,
- denominator: BigNumber,
- target: BigNumber,
- ): Promise<boolean> {
- return testExchange.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'isRoundingErrorCeil',
- referenceIsRoundingErrorCeilAsync,
- testIsRoundingErrorCeilAsync,
- [uint256Values, uint256Values, uint256Values],
- );
- });
-
- describe('updateFilledState', async () => {
- // Note(albrow): Since updateFilledState modifies the state by calling
- // sendTransaction, we must reset the state after each test.
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- async function referenceUpdateFilledStateAsync(
- takerAssetFilledAmount: BigNumber,
- orderTakerAssetFilledAmount: BigNumber,
- // tslint:disable-next-line:no-unused-variable
- orderHash: string,
- ): Promise<BigNumber> {
- const totalFilledAmount = takerAssetFilledAmount.add(orderTakerAssetFilledAmount);
- if (totalFilledAmount.greaterThan(MAX_UINT256)) {
- throw overflowErrorForSendTransaction;
- }
- return totalFilledAmount;
- }
- async function testUpdateFilledStateAsync(
- takerAssetFilledAmount: BigNumber,
- orderTakerAssetFilledAmount: BigNumber,
- orderHash: string,
- ): Promise<BigNumber> {
- const fillResults = {
- makerAssetFilledAmount: new BigNumber(0),
- takerAssetFilledAmount,
- makerFeePaid: new BigNumber(0),
- takerFeePaid: new BigNumber(0),
- };
- await web3Wrapper.awaitTransactionSuccessAsync(
- await testExchange.publicUpdateFilledState.sendTransactionAsync(
- emptySignedOrder,
- constants.NULL_ADDRESS,
- orderHash,
- orderTakerAssetFilledAmount,
- fillResults,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return testExchange.filled.callAsync(orderHash);
- }
- await testCombinatoriallyWithReferenceFuncAsync(
- 'updateFilledState',
- referenceUpdateFilledStateAsync,
- testUpdateFilledStateAsync,
- [uint256Values, uint256Values, bytes32Values],
- );
- });
-});
diff --git a/packages/contracts/test/exchange/libs.ts b/packages/contracts/test/exchange/libs.ts
deleted file mode 100644
index 503ef0e0f..000000000
--- a/packages/contracts/test/exchange/libs.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-
-import { TestConstantsContract } from '../../generated-wrappers/test_constants';
-import { TestLibsContract } from '../../generated-wrappers/test_libs';
-import { artifacts } from '../../src/artifacts';
-import { addressUtils } from '../utils/address_utils';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { OrderFactory } from '../utils/order_factory';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange libs', () => {
- let signedOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let libs: TestLibsContract;
- let testConstants: TestConstantsContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const makerAddress = accounts[0];
- libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
- testConstants = await TestConstantsContract.deployFrom0xArtifactAsync(
- artifacts.TestConstants,
- provider,
- txDefaults,
- );
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: libs.address,
- makerAddress,
- feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
- makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('LibConstants', () => {
- describe('ZRX_ASSET_DATA', () => {
- it('should have the correct ZRX_ASSET_DATA', async () => {
- const isValid = await testConstants.assertValidZrxAssetData.callAsync();
- expect(isValid).to.be.equal(true);
- });
- });
- });
- // Note(albrow): These tests are designed to be supplemental to the
- // combinatorial tests in test/exchange/internal. They test specific edge
- // cases that are not covered by the combinatorial tests.
- describe('LibMath', () => {
- describe('isRoundingError', () => {
- it('should return true if there is a rounding error of 0.1%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(999);
- const target = new BigNumber(50);
- // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
- const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- it('should return false if there is a rounding of 0.09%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(9991);
- const target = new BigNumber(500);
- // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
- const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.false();
- });
- it('should return true if there is a rounding error of 0.11%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(9989);
- const target = new BigNumber(500);
- // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
- const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- });
- describe('isRoundingErrorCeil', () => {
- it('should return true if there is a rounding error of 0.1%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(1001);
- const target = new BigNumber(50);
- // rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1%
- const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- it('should return false if there is a rounding of 0.09%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(10009);
- const target = new BigNumber(500);
- // rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09%
- const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.false();
- });
- it('should return true if there is a rounding error of 0.11%', async () => {
- const numerator = new BigNumber(20);
- const denominator = new BigNumber(10011);
- const target = new BigNumber(500);
- // rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11%
- const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
- expect(isRoundingError).to.be.true();
- });
- });
- });
-
- describe('LibOrder', () => {
- describe('getOrderHash', () => {
- it('should output the correct orderHash', async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder);
- expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex);
- });
- });
- });
-});
diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts
deleted file mode 100644
index eea9992d9..000000000
--- a/packages/contracts/test/exchange/match_orders.ts
+++ /dev/null
@@ -1,1276 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
-import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { MatchOrderTester } from '../utils/match_order_tester';
-import { OrderFactory } from '../utils/order_factory';
-import { ERC20BalancesByOwner, ERC721TokenIdsByOwner } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-chaiSetup.configure();
-const expect = chai.expect;
-
-describe('matchOrders', () => {
- let makerAddressLeft: string;
- let makerAddressRight: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddressLeft: string;
- let feeRecipientAddressRight: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
-
- let erc20BalancesByOwner: ERC20BalancesByOwner;
- let erc721TokenIdsByOwner: ERC721TokenIdsByOwner;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let orderFactoryLeft: OrderFactory;
- let orderFactoryRight: OrderFactory;
-
- let erc721LeftMakerAssetIds: BigNumber[];
- let erc721RightMakerAssetIds: BigNumber[];
-
- let defaultERC20MakerAssetAddress: string;
- let defaultERC20TakerAssetAddress: string;
- let defaultERC721AssetAddress: string;
-
- let matchOrderTester: MatchOrderTester;
-
- let testExchange: TestExchangeInternalsContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Create accounts
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- // Hack(albrow): Both Prettier and TSLint insert a trailing comma below
- // but that is invalid syntax as of TypeScript version >= 2.8. We don't
- // have the right fine-grained configuration options in TSLint,
- // Prettier, or TypeScript, to reconcile this, so we will just have to
- // wait for them to sort it out. We disable TSLint and Prettier for
- // this part of the code for now. This occurs several times in this
- // file. See https://github.com/prettier/prettier/issues/4624.
- // prettier-ignore
- const usedAddresses = ([
- owner,
- makerAddressLeft,
- makerAddressRight,
- takerAddress,
- feeRecipientAddressLeft,
- // tslint:disable-next-line:trailing-comma
- feeRecipientAddressRight
- ] = _.slice(accounts, 0, 6));
- // Create wrappers
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
- // Deploy ERC20 token & ERC20 proxy
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
- // Deploy ERC721 token and proxy
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721LeftMakerAssetIds = erc721Balances[makerAddressLeft][erc721Token.address];
- erc721RightMakerAssetIds = erc721Balances[makerAddressRight][erc721Token.address];
- // Depoy exchange
- 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);
- // Authorize ERC20 and ERC721 trades by exchange
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- // Set default addresses
- defaultERC20MakerAssetAddress = erc20TokenA.address;
- defaultERC20TakerAssetAddress = erc20TokenB.address;
- defaultERC721AssetAddress = erc721Token.address;
- // Create default order parameters
- const defaultOrderParamsLeft = {
- ...constants.STATIC_ORDER_PARAMS,
- makerAddress: makerAddressLeft,
- exchangeAddress: exchange.address,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- feeRecipientAddress: feeRecipientAddressLeft,
- };
- const defaultOrderParamsRight = {
- ...constants.STATIC_ORDER_PARAMS,
- makerAddress: makerAddressRight,
- exchangeAddress: exchange.address,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- feeRecipientAddress: feeRecipientAddressRight,
- };
- const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
- orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
- const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
- orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
- // Set match order tester
- matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper, zrxToken.address);
- testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
- artifacts.TestExchangeInternals,
- provider,
- txDefaults,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('matchOrders', () => {
- beforeEach(async () => {
- erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
- erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync();
- });
-
- it('Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Assert is rounding error ceil & not rounding error floor
- // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults
- // The rounding error is derived computating how much the left maker will sell.
- const numerator = signedOrderLeft.makerAssetAmount;
- const denominator = signedOrderLeft.takerAssetAmount;
- const target = signedOrderRight.makerAssetAmount;
- const isRoundingErrorCeil = await testExchange.publicIsRoundingErrorCeil.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorCeil).to.be.true();
- const isRoundingErrorFloor = await testExchange.publicIsRoundingErrorFloor.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorFloor).to.be.false();
- // Match signedOrderLeft with signedOrderRight
- // Note that the left maker received a slightly better sell price.
- // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
- // Because the left maker received a slightly more favorable sell price, the fee
- // paid by the left taker is slightly higher than that paid by the left maker.
- // Fees can be thought of as a tax paid by the seller, derived from the sale price.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil but fail isRoundingErrorFloor', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(15), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(14), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Assert is rounding error floor & not rounding error ceil
- // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults
- // The rounding error is derived computating how much the right maker will buy.
- const numerator = signedOrderRight.takerAssetAmount;
- const denominator = signedOrderRight.makerAssetAmount;
- const target = signedOrderLeft.takerAssetAmount;
- const isRoundingErrorFloor = await testExchange.publicIsRoundingErrorFloor.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorFloor).to.be.true();
- const isRoundingErrorCeil = await testExchange.publicIsRoundingErrorCeil.callAsync(
- numerator,
- denominator,
- target,
- );
- expect(isRoundingErrorCeil).to.be.false();
- // Match signedOrderLeft with signedOrderRight
- // Note that the right maker received a slightly better purchase price.
- // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
- // Because the right maker received a slightly more favorable buy price, the fee
- // paid by the right taker is slightly higher than that paid by the right maker.
- // Fees can be thought of as a tax paid by the seller, derived from the sale price.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(15), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.7835051546391752'), 16), // 92.78%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.8571428571428571'), 16), // 92.85%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give right maker a better buy price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(83), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(49), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The correct price buy price for the right maker would yield (49/83) * 22 = 12.988 units
- // of the left maker asset. This gets rounded up to 13, giving the right maker a better price.
- // Note:
- // The maker/taker fee percentage paid on the right order differs because
- // they received different sale prices. The right maker pays a
- // fee slightly lower than the right taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5060240963855421'), 16), // 26.506%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5306122448979591'), 16), // 26.531%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give left maker a better sell price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The maker/taker fee percentage paid on the left order differs because
- // they received different sale prices. The left maker pays a fee
- // slightly lower than the left taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give right maker and right taker a favorable fee price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(83), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(49), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- });
- // Note:
- // The maker/taker fee percentage paid on the right order differs because
- // they received different sale prices. The right maker pays a
- // fee slightly lower than the right taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(16), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(22), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2650), 0), // 2650.6 rounded down tro 2650
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(2653), 0), // 2653.1 rounded down to 2653
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should give left maker and left taker a favorable fee price when rounding', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- // Note:
- // The maker/taker fee percentage paid on the left order differs because
- // they received different sale prices. The left maker pays a
- // fee slightly lower than the left taker.
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9166), 0), // 9166.6 rounded down to 9166
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(9175), 0), // 9175.2 rounded down to 9175
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAddress: makerAddressLeft,
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- feeRecipientAddress: feeRecipientAddressLeft,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2126), 0),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1063), 0),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- // Notes:
- // i.
- // The left order is fully filled by the right order, so the right maker must sell 1005 units of their asset to the left maker.
- // By selling 1005 units, the right maker should theoretically receive 502.5 units of the left maker's asset.
- // Since the transfer amount must be an integer, this value must be rounded down to 502 or up to 503.
- // ii.
- // If the right order were filled via `Exchange.fillOrder` the respective fill amounts would be [1004, 502] or [1006, 503].
- // It follows that we cannot trigger a sale of 1005 units of the right maker's asset through `Exchange.fillOrder`.
- // iii.
- // For an optimal match, the algorithm must choose either [1005, 502] or [1005, 503] as fill amounts for the right order.
- // The algorithm favors the right maker when the exchange rate must be rounded, so the final fill for the right order is [1005, 503].
- // iv.
- // The right maker fee differs from the right taker fee because their exchange rate differs.
- // The right maker always receives the better exchange and fee price.
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1005), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(503), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.2718720602069614'), 16), // 47.27%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(497), 0),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.3189087488240827'), 16), // 47.31%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow matchOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAddress: makerAddressRight,
- takerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feeRecipientAddress: feeRecipientAddressRight,
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('matchOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts when orders completely fill each other', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when left order is completely filled and right order is partially filled', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match signedOrderLeft with signedOrderRight
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // Match signedOrderLeft with signedOrderRight
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- let newERC20BalancesByOwner: ERC20BalancesByOwner;
- let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- // prettier-ignore
- [
- newERC20BalancesByOwner,
- // tslint:disable-next-line:trailing-comma
- newERC721TokenIdsByOwner
- ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- // Construct second right order
- // Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order.
- // However, we use 100/50 to ensure a partial fill as we want to go down the "left fill"
- // branch in the contract twice for this test.
- const signedOrderRight2 = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- });
- // Match signedOrderLeft with signedOrderRight2
- const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount;
- const rightTakerAssetFilledAmount = new BigNumber(0);
- const expectedTransferAmounts2 = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight2,
- takerAddress,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts2,
- leftTakerAssetFilledAmount,
- rightTakerAssetFilledAmount,
- );
- });
-
- it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
-
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- // Match orders
- let newERC20BalancesByOwner: ERC20BalancesByOwner;
- let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(6), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
- };
- // prettier-ignore
- [
- newERC20BalancesByOwner,
- // tslint:disable-next-line:trailing-comma
- newERC721TokenIdsByOwner
- ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
-
- // Create second left order
- // Note: This order needs makerAssetAmount=96/takerAssetAmount=48 to fully fill the right order.
- // However, we use 100/50 to ensure a partial fill as we want to go down the "right fill"
- // branch in the contract twice for this test.
- const signedOrderLeft2 = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
- });
- // Match signedOrderLeft2 with signedOrderRight
- const leftTakerAssetFilledAmount = new BigNumber(0);
- const takerAmountReceived = newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress].minus(
- erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
- );
- const rightTakerAssetFilledAmount = signedOrderLeft.makerAssetAmount.minus(takerAmountReceived);
- const expectedTransferAmounts2 = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft2,
- signedOrderRight,
- takerAddress,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts2,
- leftTakerAssetFilledAmount,
- rightTakerAssetFilledAmount,
- );
- });
-
- it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => {
- const feeRecipientAddress = feeRecipientAddressLeft;
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feeRecipientAddress,
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feeRecipientAddress,
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the left order maker', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = signedOrderLeft.makerAddress;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the right order maker', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = signedOrderRight.makerAddress;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the left fee recipient', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = feeRecipientAddressLeft;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if taker is also the right fee recipient', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- takerAddress = feeRecipientAddressRight;
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer the correct amounts if left maker is the left fee recipient and right maker is the right fee recipient', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('Should throw if left order is not fillable', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Cancel left order
- await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('Should throw if right order is not fillable', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Cancel right order
- await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if there is not a positive spread', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.NegativeSpreadRequired,
- );
- });
-
- it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- // We are assuming assetData fields of the right order are the
- // reverse of the left order, rather than checking equality. This
- // saves a bunch of gas, but as a result if the assetData fields are
- // off then the failure ends up happening at signature validation
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should throw if the right maker asset is not equal to the left taker asset', async () => {
- // Create orders to match
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- });
- // Match orders
- return expectTransactionFailedAsync(
- exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
- RevertReason.InvalidOrderSignature,
- );
- });
-
- it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {
- // Create orders to match
- const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: new BigNumber(1),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
-
- it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => {
- // Create orders to match
- const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
- const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- takerAssetAmount: new BigNumber(1),
- });
- const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
- });
- // Match orders
- const expectedTransferAmounts = {
- // Left Maker
- amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
- amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Right Maker
- amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
- amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
- feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- // Taker
- amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
- feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
- };
- await matchOrderTester.matchOrdersAndAssertEffectsAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts
deleted file mode 100644
index 756c72766..000000000
--- a/packages/contracts/test/exchange/signature_validator.ts
+++ /dev/null
@@ -1,522 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils';
-import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import ethUtil = require('ethereumjs-util');
-
-import {
- TestSignatureValidatorContract,
- TestSignatureValidatorSignatureValidatorApprovalEventArgs,
-} from '../../generated-wrappers/test_signature_validator';
-import { TestStaticCallReceiverContract } from '../../generated-wrappers/test_static_call_receiver';
-import { ValidatorContract } from '../../generated-wrappers/validator';
-import { WalletContract } from '../../generated-wrappers/wallet';
-import { artifacts } from '../../src/artifacts';
-import { addressUtils } from '../utils/address_utils';
-import { expectContractCallFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { LogDecoder } from '../utils/log_decoder';
-import { OrderFactory } from '../utils/order_factory';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('MixinSignatureValidator', () => {
- let signedOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let signatureValidator: TestSignatureValidatorContract;
- let testWallet: WalletContract;
- let testValidator: ValidatorContract;
- let maliciousWallet: TestStaticCallReceiverContract;
- let maliciousValidator: TestStaticCallReceiverContract;
- let signerAddress: string;
- let signerPrivateKey: Buffer;
- let notSignerAddress: string;
- let notSignerPrivateKey: Buffer;
- let signatureValidatorLogDecoder: LogDecoder;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const makerAddress = accounts[0];
- signerAddress = makerAddress;
- notSignerAddress = accounts[1];
- signatureValidator = await TestSignatureValidatorContract.deployFrom0xArtifactAsync(
- artifacts.TestSignatureValidator,
- provider,
- txDefaults,
- );
- testWallet = await WalletContract.deployFrom0xArtifactAsync(
- artifacts.Wallet,
- provider,
- txDefaults,
- signerAddress,
- );
- testValidator = await ValidatorContract.deployFrom0xArtifactAsync(
- artifacts.Validator,
- provider,
- txDefaults,
- signerAddress,
- );
- maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync(
- artifacts.TestStaticCallReceiver,
- provider,
- txDefaults,
- );
- signatureValidatorLogDecoder = new LogDecoder(web3Wrapper);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, {
- from: signerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- maliciousValidator.address,
- true,
- {
- from: signerAddress,
- },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: signatureValidator.address,
- makerAddress,
- feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
- makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
- };
- signerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- notSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(notSignerAddress)];
- orderFactory = new OrderFactory(signerPrivateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('isValidSignature', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
-
- it('should revert when signature is empty', async () => {
- const emptySignature = '0x';
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- emptySignature,
- ),
- RevertReason.LengthGreaterThan0Required,
- );
- });
-
- it('should revert when signature type is unsupported', async () => {
- const unsupportedSignatureType = SignatureType.NSignatureTypes;
- const unsupportedSignatureHex = '0x' + Buffer.from([unsupportedSignatureType]).toString('hex');
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- unsupportedSignatureHex,
- ),
- RevertReason.SignatureUnsupported,
- );
- });
-
- it('should revert when SignatureType=Illegal', async () => {
- const unsupportedSignatureHex = '0x' + Buffer.from([SignatureType.Illegal]).toString('hex');
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- unsupportedSignatureHex,
- ),
- RevertReason.SignatureIllegal,
- );
- });
-
- it('should return false when SignatureType=Invalid and signature has a length of zero', async () => {
- const signatureHex = '0x' + Buffer.from([SignatureType.Invalid]).toString('hex');
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when SignatureType=Invalid and signature length is non-zero', async () => {
- const fillerData = ethUtil.toBuffer('0xdeadbeef');
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Invalid}`);
- const signatureBuffer = Buffer.concat([fillerData, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signatureBuffer);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- return expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- ),
- RevertReason.Length0Required,
- );
- });
-
- it('should return true when SignatureType=EIP712 and signature is valid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EIP712}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=EIP712 and signature is invalid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EIP712}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature.
- // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=EthSign and signature is valid', async () => {
- // Create EthSign signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
- const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
- const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
- // Create 0x signature from EthSign signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EthSign}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=EthSign and signature is invalid', async () => {
- // Create EthSign signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
- const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
- const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
- // Create 0x signature from EthSign signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.EthSign}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature.
- // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=Wallet and signature is valid', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- testWallet.address,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Wallet and signature is invalid', async () => {
- // Create EIP712 signature using a private key that does not belong to the wallet owner.
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const notWalletOwnerPrivateKey = notSignerPrivateKey;
- const ecSignature = ethUtil.ecsign(orderHashBuffer, notWalletOwnerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- // Validate signature
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- testWallet.address,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when `isValidSignature` attempts to update state and SignatureType=Wallet', async () => {
- // Create EIP712 signature
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const orderHashBuffer = ethUtil.toBuffer(orderHashHex);
- const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey);
- // Create 0x signature from EIP712 signature
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(`0x${SignatureType.Wallet}`),
- ]);
- const signatureHex = ethUtil.bufferToHex(signature);
- await expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- maliciousWallet.address,
- signatureHex,
- ),
- RevertReason.WalletError,
- );
- });
-
- it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => {
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Validator, signature is invalid and validator is approved', async () => {
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- // This will return false because we signed the message with `signerAddress`, but
- // are validating against `notSignerAddress`
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- notSignerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should revert when `isValidSignature` attempts to update state and SignatureType=Validator', async () => {
- const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- await expectContractCallFailedAsync(
- signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex),
- RevertReason.ValidatorError,
- );
- });
- it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => {
- // Set approval of signature validator to false
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- false,
- { from: signerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Validate signature
- const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`);
- const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`);
- const signature = Buffer.concat([validatorAddress, signatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when SignatureType=Presigned and signer has presigned hash', async () => {
- // Presign hash
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await signatureValidator.preSign.sendTransactionAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signedOrder.signature,
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- // Validate presigned signature
- const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return false when SignatureType=Presigned and signer has not presigned hash', async () => {
- const signature = ethUtil.toBuffer(`0x${SignatureType.PreSigned}`);
- const signatureHex = ethUtil.bufferToHex(signature);
- const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- orderHashHex,
- signedOrder.makerAddress,
- signatureHex,
- );
- expect(isValidSignature).to.be.false();
- });
-
- it('should return true when message was signed by a Trezor One (firmware version 1.6.2)', async () => {
- // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
- const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
- const signer = '0xc28b145f10f0bcf0fc000e778615f8fd73490bad';
- const v = ethUtil.toBuffer('0x1c');
- const r = ethUtil.toBuffer('0x7b888b596ccf87f0bacab0dcb483124973f7420f169b4824d7a12534ac1e9832');
- const s = ethUtil.toBuffer('0x0c8e14f7edc01459e13965f1da56e0c23ed11e2cca932571eee1292178f90424');
- const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
- const signature = Buffer.concat([v, r, s, trezorSignatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- messageHash,
- signer,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
-
- it('should return true when message was signed by a Trezor Model T (firmware version 2.0.7)', async () => {
- // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
- const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++'));
- const signer = '0x98ce6d9345e8ffa7d99ee0822272fae9d2c0e895';
- const v = ethUtil.toBuffer('0x1c');
- const r = ethUtil.toBuffer('0x423b71062c327f0ec4fe199b8da0f34185e59b4c1cb4cc23df86cac4a601fb3f');
- const s = ethUtil.toBuffer('0x53810d6591b5348b7ee08ee812c874b0fdfb942c9849d59512c90e295221091f');
- const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`);
- const signature = Buffer.concat([v, r, s, trezorSignatureType]);
- const signatureHex = ethUtil.bufferToHex(signature);
- const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync(
- messageHash,
- signer,
- signatureHex,
- );
- expect(isValidSignature).to.be.true();
- });
- });
-
- describe('setSignatureValidatorApproval', () => {
- it('should emit a SignatureValidatorApprovalSet with correct args when a validator is approved', async () => {
- const approval = true;
- const res = await signatureValidatorLogDecoder.getTxWithDecodedLogsAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- approval,
- {
- from: signerAddress,
- },
- ),
- );
- expect(res.logs.length).to.equal(1);
- const log = res.logs[0] as LogWithDecodedArgs<TestSignatureValidatorSignatureValidatorApprovalEventArgs>;
- const logArgs = log.args;
- expect(logArgs.signerAddress).to.equal(signerAddress);
- expect(logArgs.validatorAddress).to.equal(testValidator.address);
- expect(logArgs.approved).to.equal(approval);
- });
- it('should emit a SignatureValidatorApprovalSet with correct args when a validator is disapproved', async () => {
- const approval = false;
- const res = await signatureValidatorLogDecoder.getTxWithDecodedLogsAsync(
- await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(
- testValidator.address,
- approval,
- {
- from: signerAddress,
- },
- ),
- );
- expect(res.logs.length).to.equal(1);
- const log = res.logs[0] as LogWithDecodedArgs<TestSignatureValidatorSignatureValidatorApprovalEventArgs>;
- const logArgs = log.args;
- expect(logArgs.signerAddress).to.equal(signerAddress);
- expect(logArgs.validatorAddress).to.equal(testValidator.address);
- expect(logArgs.approved).to.equal(approval);
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/exchange/transactions.ts b/packages/contracts/test/exchange/transactions.ts
deleted file mode 100644
index 1b5eef295..000000000
--- a/packages/contracts/test/exchange/transactions.ts
+++ /dev/null
@@ -1,462 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { OrderWithoutExchangeAddress, RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ExchangeWrapperContract } from '../../generated-wrappers/exchange_wrapper';
-import { WhitelistContract } from '../../generated-wrappers/whitelist';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { orderUtils } from '../utils/order_utils';
-import { TransactionFactory } from '../utils/transaction_factory';
-import { ERC20BalancesByOwner, SignedTransaction } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange transactions', () => {
- let senderAddress: string;
- let owner: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
-
- let erc20Balances: ERC20BalancesByOwner;
- let signedOrder: SignedOrder;
- let signedTx: SignedTransaction;
- let orderWithoutExchangeAddress: OrderWithoutExchangeAddress;
- let orderFactory: OrderFactory;
- let makerTransactionFactory: TransactionFactory;
- let takerTransactionFactory: TransactionFactory;
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
-
- let defaultMakerTokenAddress: string;
- let defaultTakerTokenAddress: string;
- let makerPrivateKey: Buffer;
- let takerPrivateKey: Buffer;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, senderAddress, makerAddress, takerAddress, feeRecipientAddress] = _.slice(
- accounts,
- 0,
- 5,
- ));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- assetDataUtils.encodeERC20AssetData(zrxToken.address),
- );
- exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- defaultMakerTokenAddress = erc20TokenA.address;
- defaultTakerTokenAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- senderAddress,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerTokenAddress),
- };
- makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
- orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
- makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
- takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
- });
- describe('executeTransaction', () => {
- describe('fillOrder', () => {
- let takerAssetFillAmount: BigNumber;
- beforeEach(async () => {
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- signedOrder = await orderFactory.newSignedOrderAsync();
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
-
- takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const data = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- signedTx = takerTransactionFactory.newSignedTransaction(data);
- });
-
- it('should throw if not called by specified sender', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, takerAddress),
- RevertReason.FailedExecution,
- );
- });
-
- it('should transfer the correct amounts when signed by taker and called by sender', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFeePaid = signedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFeePaid = signedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
- );
- });
-
- it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, senderAddress),
- RevertReason.InvalidTxHash,
- );
- });
-
- it('should reset the currentContextAddress', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- const currentContextAddress = await exchange.currentContextAddress.callAsync();
- expect(currentContextAddress).to.equal(constants.NULL_ADDRESS);
- });
- });
-
- describe('cancelOrder', () => {
- beforeEach(async () => {
- const data = exchange.cancelOrder.getABIEncodedTransactionData(orderWithoutExchangeAddress);
- signedTx = makerTransactionFactory.newSignedTransaction(data);
- });
-
- it('should throw if not called by specified sender', async () => {
- return expectTransactionFailedAsync(
- exchangeWrapper.executeTransactionAsync(signedTx, makerAddress),
- RevertReason.FailedExecution,
- );
- });
-
- it('should cancel the order when signed by maker and called by sender', async () => {
- await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrderAsync(signedOrder, senderAddress),
- RevertReason.OrderUnfillable,
- );
- });
- });
-
- describe('cancelOrdersUpTo', () => {
- let exchangeWrapperContract: ExchangeWrapperContract;
-
- before(async () => {
- exchangeWrapperContract = await ExchangeWrapperContract.deployFrom0xArtifactAsync(
- artifacts.ExchangeWrapper,
- provider,
- txDefaults,
- exchange.address,
- );
- });
-
- it("should cancel an order if called from the order's sender", async () => {
- const orderSalt = new BigNumber(0);
- signedOrder = await orderFactory.newSignedOrderAsync({
- senderAddress: exchangeWrapperContract.address,
- salt: orderSalt,
- });
- const targetOrderEpoch = orderSalt.add(1);
- const cancelData = exchange.cancelOrdersUpTo.getABIEncodedTransactionData(targetOrderEpoch);
- const signedCancelTx = makerTransactionFactory.newSignedTransaction(cancelData);
- await exchangeWrapperContract.cancelOrdersUpTo.sendTransactionAsync(
- targetOrderEpoch,
- signedCancelTx.salt,
- signedCancelTx.signature,
- {
- from: makerAddress,
- },
- );
-
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const fillData = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- const signedFillTx = takerTransactionFactory.newSignedTransaction(fillData);
- return expectTransactionFailedAsync(
- exchangeWrapperContract.fillOrder.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedFillTx.salt,
- signedOrder.signature,
- signedFillTx.signature,
- { from: takerAddress },
- ),
- RevertReason.FailedExecution,
- );
- });
-
- it("should not cancel an order if not called from the order's sender", async () => {
- const orderSalt = new BigNumber(0);
- signedOrder = await orderFactory.newSignedOrderAsync({
- senderAddress: exchangeWrapperContract.address,
- salt: orderSalt,
- });
- const targetOrderEpoch = orderSalt.add(1);
- await exchangeWrapper.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress);
-
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const data = exchange.fillOrder.getABIEncodedTransactionData(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedOrder.signature,
- );
- signedTx = takerTransactionFactory.newSignedTransaction(data);
- await exchangeWrapperContract.fillOrder.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- signedTx.salt,
- signedOrder.signature,
- signedTx.signature,
- { from: takerAddress },
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFillAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFeePaid = signedOrder.makerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFeePaid = signedOrder.takerFee
- .times(makerAssetFillAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
- );
- });
- });
- });
-
- describe('Whitelist', () => {
- let whitelist: WhitelistContract;
- let whitelistOrderFactory: OrderFactory;
-
- before(async () => {
- whitelist = await WhitelistContract.deployFrom0xArtifactAsync(
- artifacts.Whitelist,
- provider,
- txDefaults,
- exchange.address,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await exchange.setSignatureValidatorApproval.sendTransactionAsync(whitelist.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- senderAddress: whitelist.address,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerTokenAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerTokenAddress),
- };
- whitelistOrderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- signedOrder = await whitelistOrderFactory.newSignedOrderAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
-
- it('should revert if maker has not been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- return expectTransactionFailedAsync(
- whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- RevertReason.MakerNotWhitelisted,
- );
- });
-
- it('should revert if taker has not been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- return expectTransactionFailedAsync(
- whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- RevertReason.TakerNotWhitelisted,
- );
- });
-
- it('should fill the order if maker and taker have been whitelisted', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- const salt = generatePseudoRandomSalt();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
- orderWithoutExchangeAddress,
- takerAssetFillAmount,
- salt,
- signedOrder.signature,
- { from: takerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFillAmount = signedOrder.makerAssetAmount;
- const makerFeePaid = signedOrder.makerFee;
- const takerFeePaid = signedOrder.takerFee;
-
- expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)),
- );
- });
- });
-});
diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts
deleted file mode 100644
index 6b660aac5..000000000
--- a/packages/contracts/test/exchange/wrapper.ts
+++ /dev/null
@@ -1,1452 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ReentrantERC20TokenContract } from '../../generated-wrappers/reentrant_erc20_token';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync } from '../utils/assertions';
-import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { ERC20BalancesByOwner, OrderStatus } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('Exchange wrappers', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
-
- let erc20TokenA: DummyERC20TokenContract;
- let erc20TokenB: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let exchange: ExchangeContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
- let reentrantErc20Token: ReentrantERC20TokenContract;
-
- let exchangeWrapper: ExchangeWrapper;
- let erc20Wrapper: ERC20Wrapper;
- let erc721Wrapper: ERC721Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let orderFactory: OrderFactory;
-
- let erc721MakerAssetId: BigNumber;
- let erc721TakerAssetId: BigNumber;
-
- let defaultMakerAssetAddress: string;
- let defaultTakerAssetAddress: string;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = _.slice(accounts, 0, 4));
-
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- 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();
- erc721MakerAssetId = erc721Balances[makerAddress][erc721Token.address][0];
- erc721TakerAssetId = erc721Balances[takerAddress][erc721Token.address][0];
-
- 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);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
- from: owner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.ReentrantERC20Token,
- provider,
- txDefaults,
- exchange.address,
- );
-
- defaultMakerAssetAddress = erc20TokenA.address;
- defaultTakerAssetAddress = erc20TokenB.address;
-
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('fillOrKillOrder', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrKillOrder to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('fillOrKillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- await exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should throw if a signedOrder is expired', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const signedOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp).sub(10),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.OrderUnfillable,
- );
- });
-
- it('should throw if entire takerAssetFillAmount not filled', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
-
- await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
- });
-
- return expectTransactionFailedAsync(
- exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
- RevertReason.CompleteFillFailed,
- );
- });
- });
-
- describe('fillOrderNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow fillOrderNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('fillOrderNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- });
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 250000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
-
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should not change erc20Balances if maker erc20Balances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
- });
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if taker erc20Balances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
- });
-
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if maker allowances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenA.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if taker allowances are too low to fill order', async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync();
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, new BigNumber(0), {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20TokenB.approve.sendTransactionAsync(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if makerAssetAddress is ZRX, makerAssetAmount + makerFee > maker balance', async () => {
- const makerZRXBalance = new BigNumber(erc20Balances[makerAddress][zrxToken.address]);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: makerZRXBalance,
- makerFee: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if makerAssetAddress is ZRX, makerAssetAmount + makerFee > maker allowance', async () => {
- const makerZRXAllowance = await zrxToken.allowance.callAsync(makerAddress, erc20Proxy.address);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(makerZRXAllowance),
- makerFee: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if takerAssetAddress is ZRX, takerAssetAmount + takerFee > taker balance', async () => {
- const takerZRXBalance = new BigNumber(erc20Balances[takerAddress][zrxToken.address]);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: takerZRXBalance,
- takerFee: new BigNumber(1),
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not change erc20Balances if takerAssetAddress is ZRX, takerAssetAmount + takerFee > taker allowance', async () => {
- const takerZRXAllowance = await zrxToken.allowance.callAsync(takerAddress, erc20Proxy.address);
- const signedOrder = await orderFactory.newSignedOrderAsync({
- takerAssetAmount: new BigNumber(takerZRXAllowance),
- takerFee: new BigNumber(1),
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- });
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should successfully exchange ERC721 tokens', async () => {
- // Construct Exchange parameters
- const makerAssetId = erc721MakerAssetId;
- const takerAssetId = erc721TakerAssetId;
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- takerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
- });
- // Verify pre-conditions
- const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress);
- const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
- // Call Exchange
- const takerAssetFillAmount = signedOrder.takerAssetAmount;
- await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 280000,
- });
- // Verify post-conditions
- const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
- expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
- const newOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
- expect(newOwnerTakerAsset).to.be.bignumber.equal(makerAddress);
- });
- });
-
- describe('batch functions', () => {
- let signedOrders: SignedOrder[];
- beforeEach(async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- });
-
- describe('batchFillOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('batchFillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('batchFillOrKillOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrKillOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('batchFillOrKillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- await exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw if a single signedOrder does not fill the expected amount', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- });
-
- await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
-
- return expectTransactionFailedAsync(
- exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- }),
- RevertReason.OrderUnfillable,
- );
- });
- });
-
- describe('batchFillOrdersNoThrow', async () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow batchFillOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.batchFillOrdersNoThrowAsync([signedOrder], takerAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('batchFillOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should transfer the correct amounts', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
- _.forEach(signedOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not throw if an order is invalid and fill the remaining orders', async () => {
- const takerAssetFillAmounts: BigNumber[] = [];
- const makerAssetAddress = erc20TokenA.address;
- const takerAssetAddress = erc20TokenB.address;
-
- const invalidOrder = {
- ...signedOrders[0],
- signature: '0x00',
- };
- const validOrders = signedOrders.slice(1);
-
- takerAssetFillAmounts.push(invalidOrder.takerAssetAmount.div(2));
- _.forEach(validOrders, signedOrder => {
- const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
- const makerAssetFilledAmount = takerAssetFillAmount
- .times(signedOrder.makerAssetAmount)
- .dividedToIntegerBy(signedOrder.takerAssetAmount);
- const makerFee = signedOrder.makerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- const takerFee = signedOrder.takerFee
- .times(makerAssetFilledAmount)
- .dividedToIntegerBy(signedOrder.makerAssetAmount);
- takerAssetFillAmounts.push(takerAssetFillAmount);
- erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
- makerAssetAddress
- ].minus(makerAssetFilledAmount);
- erc20Balances[makerAddress][takerAssetAddress] = erc20Balances[makerAddress][takerAssetAddress].add(
- takerAssetFillAmount,
- );
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- makerFee,
- );
- erc20Balances[takerAddress][makerAssetAddress] = erc20Balances[takerAddress][makerAssetAddress].add(
- makerAssetFilledAmount,
- );
- erc20Balances[takerAddress][takerAssetAddress] = erc20Balances[takerAddress][
- takerAssetAddress
- ].minus(takerAssetFillAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(makerFee.add(takerFee));
- });
-
- const newOrders = [invalidOrder, ...validOrders];
- await exchangeWrapper.batchFillOrdersNoThrowAsync(newOrders, takerAddress, {
- takerAssetFillAmounts,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 450000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('marketSellOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketSellOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount,
- }),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('marketSellOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire takerAssetFillAmount is filled', async () => {
- const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.div(2),
- );
- await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.add(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw when a signedOrder does not use the same takerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- await orderFactory.newSignedOrderAsync(),
- ];
-
- return expectTransactionFailedAsync(
- exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
- takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
- }),
- // We simply use the takerAssetData from the first order for all orders.
- // If they are not the same, the contract throws when validating the order signature
- RevertReason.InvalidOrderSignature,
- );
- });
- });
-
- describe('marketSellOrdersNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketSellOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.marketSellOrdersNoThrowAsync([signedOrder], takerAddress, {
- takerAssetFillAmount: signedOrder.takerAssetAmount,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('marketSellOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire takerAssetFillAmount is filled', async () => {
- const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
- signedOrders[1].takerAssetAmount.div(2),
- );
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 6000000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.add(
- signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFilledAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not fill a signedOrder that does not use the same takerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- ];
- const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- const filledSignedOrders = signedOrders.slice(0, -1);
- _.forEach(filledSignedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('marketBuyOrders', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketBuyOrders to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await expectTransactionFailedAsync(
- exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, {
- makerAssetFillAmount: signedOrder.makerAssetAmount,
- }),
- RevertReason.TransferFailed,
- );
- });
- });
- };
- describe('marketBuyOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire makerAssetFillAmount is filled', async () => {
- const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.div(2),
- );
- await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAmountBought = signedOrders[0].takerAssetAmount.add(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(makerAmountBought),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should throw when a signedOrder does not use the same makerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- await orderFactory.newSignedOrderAsync(),
- ];
-
- return expectTransactionFailedAsync(
- exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
- makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
- }),
- RevertReason.InvalidOrderSignature,
- );
- });
- });
-
- describe('marketBuyOrdersNoThrow', () => {
- const reentrancyTest = (functionNames: string[]) => {
- _.forEach(functionNames, async (functionName: string, functionId: number) => {
- const description = `should not allow marketBuyOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
- it(description, async () => {
- const signedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
- });
- await web3Wrapper.awaitTransactionSuccessAsync(
- await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await exchangeWrapper.marketBuyOrdersNoThrowAsync([signedOrder], takerAddress, {
- makerAssetFillAmount: signedOrder.makerAssetAmount,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.deep.equal(newBalances);
- });
- });
- };
- describe('marketBuyOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX));
-
- it('should stop when the entire makerAssetFillAmount is filled', async () => {
- const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
- signedOrders[1].makerAssetAmount.div(2),
- );
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAmountBought = signedOrders[0].takerAssetAmount.add(
- signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
- );
- const makerFee = signedOrders[0].makerFee.add(signedOrders[1].makerFee.dividedToIntegerBy(2));
- const takerFee = signedOrders[0].takerFee.add(signedOrders[1].takerFee.dividedToIntegerBy(2));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultTakerAssetAddress].add(makerAmountBought),
- );
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerFee),
- );
- expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].minus(takerFee),
- );
- expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFee.add(takerFee)),
- );
- });
-
- it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- _.forEach(signedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
-
- it('should not fill a signedOrder that does not use the same makerAssetAddress', async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- }),
- ];
-
- const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
- const filledSignedOrders = signedOrders.slice(0, -1);
- _.forEach(filledSignedOrders, signedOrder => {
- erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
- defaultMakerAssetAddress
- ].minus(signedOrder.makerAssetAmount);
- erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
- defaultTakerAssetAddress
- ].add(signedOrder.takerAssetAmount);
- erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
- signedOrder.makerFee,
- );
- erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
- defaultMakerAssetAddress
- ].add(signedOrder.makerAssetAmount);
- erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
- defaultTakerAssetAddress
- ].minus(signedOrder.takerAssetAmount);
- erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
- signedOrder.takerFee,
- );
- erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
- zrxToken.address
- ].add(signedOrder.makerFee.add(signedOrder.takerFee));
- });
- await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
- makerAssetFillAmount,
- // HACK(albrow): We need to hardcode the gas estimate here because
- // the Geth gas estimator doesn't work with the way we use
- // delegatecall and swallow errors.
- gas: 600000,
- });
-
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances).to.be.deep.equal(erc20Balances);
- });
- });
-
- describe('batchCancelOrders', () => {
- it('should be able to cancel multiple signedOrders', async () => {
- const takerAssetCancelAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount);
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
-
- await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
- takerAssetFillAmounts: takerAssetCancelAmounts,
- });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(erc20Balances).to.be.deep.equal(newBalances);
- });
- });
-
- describe('getOrdersInfo', () => {
- beforeEach(async () => {
- signedOrders = [
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- await orderFactory.newSignedOrderAsync(),
- ];
- });
- it('should get the correct information for multiple unfilled orders', async () => {
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.FILLABLE;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.FILLABLE;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple fully filled orders', async () => {
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
- const expectedOrderStatus = OrderStatus.FULLY_FILLED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple cancelled and unfilled orders', async () => {
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.CANCELLED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple cancelled and partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.CANCELLED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple expired and unfilled orders', async () => {
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = new BigNumber(0);
- const expectedOrderStatus = OrderStatus.EXPIRED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for multiple expired and partially filled orders', async () => {
- const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
- await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
- await increaseTimeAndMineBlockAsync(timeUntilExpiration);
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(3);
- _.forEach(signedOrders, (signedOrder, index) => {
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
- const expectedOrderStatus = OrderStatus.EXPIRED;
- const orderInfo = ordersInfo[index];
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
- expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
- });
- });
- it('should get the correct information for a mix of unfilled, partially filled, fully filled, cancelled, and expired orders', async () => {
- const unfilledOrder = await orderFactory.newSignedOrderAsync();
- const partiallyFilledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(partiallyFilledOrder, takerAddress, {
- takerAssetFillAmount: partiallyFilledOrder.takerAssetAmount.div(2),
- });
- const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.fillOrderAsync(fullyFilledOrder, takerAddress);
- const cancelledOrder = await orderFactory.newSignedOrderAsync();
- await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
- const currentTimestamp = await getLatestBlockTimestampAsync();
- const expiredOrder = await orderFactory.newSignedOrderAsync({
- expirationTimeSeconds: new BigNumber(currentTimestamp),
- });
- signedOrders = [unfilledOrder, partiallyFilledOrder, fullyFilledOrder, cancelledOrder, expiredOrder];
- const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
- expect(ordersInfo.length).to.be.equal(5);
-
- const expectedUnfilledOrderHash = orderHashUtils.getOrderHashHex(unfilledOrder);
- const expectedUnfilledTakerAssetFilledAmount = new BigNumber(0);
- const expectedUnfilledOrderStatus = OrderStatus.FILLABLE;
- const unfilledOrderInfo = ordersInfo[0];
- expect(unfilledOrderInfo.orderHash).to.be.equal(expectedUnfilledOrderHash);
- expect(unfilledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedUnfilledTakerAssetFilledAmount,
- );
- expect(unfilledOrderInfo.orderStatus).to.be.equal(expectedUnfilledOrderStatus);
-
- const expectedPartialOrderHash = orderHashUtils.getOrderHashHex(partiallyFilledOrder);
- const expectedPartialTakerAssetFilledAmount = partiallyFilledOrder.takerAssetAmount.div(2);
- const expectedPartialOrderStatus = OrderStatus.FILLABLE;
- const partialOrderInfo = ordersInfo[1];
- expect(partialOrderInfo.orderHash).to.be.equal(expectedPartialOrderHash);
- expect(partialOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedPartialTakerAssetFilledAmount,
- );
- expect(partialOrderInfo.orderStatus).to.be.equal(expectedPartialOrderStatus);
-
- const expectedFilledOrderHash = orderHashUtils.getOrderHashHex(fullyFilledOrder);
- const expectedFilledTakerAssetFilledAmount = fullyFilledOrder.takerAssetAmount;
- const expectedFilledOrderStatus = OrderStatus.FULLY_FILLED;
- const filledOrderInfo = ordersInfo[2];
- expect(filledOrderInfo.orderHash).to.be.equal(expectedFilledOrderHash);
- expect(filledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedFilledTakerAssetFilledAmount,
- );
- expect(filledOrderInfo.orderStatus).to.be.equal(expectedFilledOrderStatus);
-
- const expectedCancelledOrderHash = orderHashUtils.getOrderHashHex(cancelledOrder);
- const expectedCancelledTakerAssetFilledAmount = new BigNumber(0);
- const expectedCancelledOrderStatus = OrderStatus.CANCELLED;
- const cancelledOrderInfo = ordersInfo[3];
- expect(cancelledOrderInfo.orderHash).to.be.equal(expectedCancelledOrderHash);
- expect(cancelledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedCancelledTakerAssetFilledAmount,
- );
- expect(cancelledOrderInfo.orderStatus).to.be.equal(expectedCancelledOrderStatus);
-
- const expectedExpiredOrderHash = orderHashUtils.getOrderHashHex(expiredOrder);
- const expectedExpiredTakerAssetFilledAmount = new BigNumber(0);
- const expectedExpiredOrderStatus = OrderStatus.EXPIRED;
- const expiredOrderInfo = ordersInfo[4];
- expect(expiredOrderInfo.orderHash).to.be.equal(expectedExpiredOrderHash);
- expect(expiredOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
- expectedExpiredTakerAssetFilledAmount,
- );
- expect(expiredOrderInfo.orderStatus).to.be.equal(expectedExpiredOrderStatus);
- });
- });
- });
-}); // tslint:disable-line:max-file-line-count
diff --git a/packages/contracts/test/extensions/forwarder.ts b/packages/contracts/test/extensions/forwarder.ts
deleted file mode 100644
index c006be0fe..000000000
--- a/packages/contracts/test/extensions/forwarder.ts
+++ /dev/null
@@ -1,1282 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils } from '@0x/order-utils';
-import { RevertReason, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { ForwarderContract } from '../../generated-wrappers/forwarder';
-import { WETH9Contract } from '../../generated-wrappers/weth9';
-import { artifacts } from '../../src/artifacts';
-import {
- expectContractCreationFailedAsync,
- expectTransactionFailedAsync,
- sendTransactionResult,
-} from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { ForwarderWrapper } from '../utils/forwarder_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { ContractName, ERC20BalancesByOwner } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const DECIMALS_DEFAULT = 18;
-const MAX_WETH_FILL_PERCENTAGE = 95;
-
-describe(ContractName.Forwarder, () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let feeRecipientAddress: string;
- let otherAddress: string;
- let defaultMakerAssetAddress: string;
- let zrxAssetData: string;
- let wethAssetData: string;
-
- let weth: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc20TokenA: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let forwarderContract: ForwarderContract;
- let wethContract: WETH9Contract;
- let forwarderWrapper: ForwarderWrapper;
- let exchangeWrapper: ExchangeWrapper;
-
- let orderWithoutFee: SignedOrder;
- let orderWithFee: SignedOrder;
- let feeOrder: SignedOrder;
- let orderFactory: OrderFactory;
- let erc20Wrapper: ERC20Wrapper;
- let erc20Balances: ERC20BalancesByOwner;
- let tx: TransactionReceiptWithDecodedLogs;
-
- let erc721MakerAssetIds: BigNumber[];
- let takerEthBalanceBefore: BigNumber;
- let feePercentage: BigNumber;
- let gasPrice: BigNumber;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress, otherAddress] = accounts);
-
- const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 });
- const transaction = await web3Wrapper.getTransactionByHashAsync(txHash);
- gasPrice = new BigNumber(transaction.gasPrice);
-
- const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
- erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 3;
- [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- const erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- const erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
- erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
-
- wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults);
- weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider);
- erc20Wrapper.addDummyTokenContract(weth);
-
- wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
- zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
- from: owner,
- });
-
- defaultMakerAssetAddress = erc20TokenA.address;
- const defaultTakerAssetAddress = wethContract.address;
- const defaultOrderParams = {
- exchangeAddress: exchangeInstance.address,
- makerAddress,
- feeRecipientAddress,
- makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
- takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT),
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT),
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
-
- const forwarderInstance = await ForwarderContract.deployFrom0xArtifactAsync(
- artifacts.Forwarder,
- provider,
- txDefaults,
- exchangeInstance.address,
- zrxAssetData,
- wethAssetData,
- );
- forwarderContract = new ForwarderContract(forwarderInstance.abi, forwarderInstance.address, provider);
- forwarderWrapper = new ForwarderWrapper(forwarderContract, provider);
- const zrxDepositAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transfer.sendTransactionAsync(forwarderContract.address, zrxDepositAmount),
- );
- erc20Wrapper.addTokenOwnerAddress(forwarderInstance.address);
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- erc20Balances = await erc20Wrapper.getBalancesAsync();
- takerEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- orderWithoutFee = await orderFactory.newSignedOrderAsync();
- feeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- orderWithFee = await orderFactory.newSignedOrderAsync({
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('constructor', () => {
- it('should revert if assetProxy is unregistered', async () => {
- const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- return expectContractCreationFailedAsync(
- (ForwarderContract.deployFrom0xArtifactAsync(
- artifacts.Forwarder,
- provider,
- txDefaults,
- exchangeInstance.address,
- zrxAssetData,
- wethAssetData,
- ) as any) as sendTransactionResult,
- RevertReason.UnregisteredAssetProxy,
- );
- });
- });
- describe('marketSellOrdersWithEth without extra fees', () => {
- it('should fill a single order', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill multiple orders', async () => {
- const secondOrderWithoutFee = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [orderWithoutFee, secondOrderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = ordersWithoutFee[0].takerAssetAmount.plus(
- ordersWithoutFee[1].takerAssetAmount.dividedToIntegerBy(2),
- );
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const firstTakerAssetFillAmount = ordersWithoutFee[0].takerAssetAmount;
- const secondTakerAssetFillAmount = primaryTakerAssetFillAmount.minus(firstTakerAssetFillAmount);
-
- const makerAssetFillAmount = ordersWithoutFee[0].makerAssetAmount.plus(
- ordersWithoutFee[1].makerAssetAmount
- .times(secondTakerAssetFillAmount)
- .dividedToIntegerBy(ordersWithoutFee[1].takerAssetAmount),
- );
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill the order and pay ZRX fees from a single feeOrder', async () => {
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- const ethValue = orderWithFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const feeAmount = ForwarderWrapper.getPercentageOfValue(
- orderWithFee.takerFee.dividedToIntegerBy(2),
- MAX_WETH_FILL_PERCENTAGE,
- );
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const totalEthSpent = primaryTakerAssetFillAmount
- .plus(wethSpentOnFeeOrders)
- .plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill the orders and pay ZRX from multiple feeOrders', async () => {
- const ordersWithFee = [orderWithFee];
- const ethValue = orderWithFee.takerAssetAmount;
- const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const makerAssetAmount = orderWithFee.takerFee.dividedToIntegerBy(2);
- const takerAssetAmount = feeOrder.takerAssetAmount
- .times(makerAssetAmount)
- .dividedToIntegerBy(feeOrder.makerAssetAmount);
-
- const firstFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const secondFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const feeOrders = [firstFeeOrder, secondFeeOrder];
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const feeAmount = ForwarderWrapper.getPercentageOfValue(orderWithFee.takerFee, MAX_WETH_FILL_PERCENTAGE);
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const totalEthSpent = primaryTakerAssetFillAmount
- .plus(wethSpentOnFeeOrders)
- .plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fill the order when token is ZRX with fees', async () => {
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2);
- const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed));
- const takerFeePaid = orderWithFee.takerFee.dividedToIntegerBy(2);
- const makerFeePaid = orderWithFee.makerFee.dividedToIntegerBy(2);
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount).minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount).minus(takerFeePaid),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(ethValue),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[forwarderContract.address][zrxToken.address],
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithoutFee.takerAssetAmount.times(2);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const totalEthSpent = orderWithoutFee.takerAssetAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- });
- it('should revert if ZRX cannot be fully repurchased', async () => {
- orderWithFee = await orderFactory.newSignedOrderAsync({
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- feeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const feeOrders = [feeOrder];
- const ethValue = orderWithFee.takerAssetAmount;
- return expectTransactionFailedAsync(
- forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- }),
- RevertReason.CompleteFillFailed,
- );
- });
- it('should not fill orders with different makerAssetData than the first order', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- const erc721SignedOrder = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- });
- const erc20SignedOrder = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [erc20SignedOrder, erc721SignedOrder];
- const feeOrders: SignedOrder[] = [];
- const ethValue = erc20SignedOrder.takerAssetAmount.plus(erc721SignedOrder.takerAssetAmount);
-
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(ordersWithoutFee, feeOrders, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const totalEthSpent = erc20SignedOrder.takerAssetAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- });
- });
- describe('marketSellOrdersWithEth with extra fees', () => {
- it('should fill the order and send fee to feeRecipient', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const ethValue = orderWithoutFee.takerAssetAmount.div(2);
-
- const baseFeePercentage = 2;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- tx = await forwarderWrapper.marketSellOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- );
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getPercentageOfValue(
- ethValue,
- MAX_WETH_FILL_PERCENTAGE,
- );
- const makerAssetFillAmount = primaryTakerAssetFillAmount
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- const ethSpentOnFee = ForwarderWrapper.getPercentageOfValue(primaryTakerAssetFillAmount, baseFeePercentage);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(ethSpentOnFee).plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(feeRecipientEthBalanceAfter).to.be.bignumber.equal(feeRecipientEthBalanceBefore.plus(ethSpentOnFee));
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fail if the fee is set too high', async () => {
- const ethValue = orderWithoutFee.takerAssetAmount.div(2);
- const baseFeePercentage = 6;
- feePercentage = ForwarderWrapper.getPercentageOfValue(ethValue, baseFeePercentage);
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- await expectTransactionFailedAsync(
- forwarderWrapper.marketSellOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- { from: takerAddress, value: ethValue, gasPrice },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.FeePercentageTooLarge,
- );
- });
- it('should fail if there is not enough ETH remaining to pay the fee', async () => {
- const ethValue = orderWithoutFee.takerAssetAmount.div(2);
- const baseFeePercentage = 5;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- await expectTransactionFailedAsync(
- forwarderWrapper.marketSellOrdersWithEthAsync(
- ordersWithFee,
- feeOrders,
- { from: takerAddress, value: ethValue, gasPrice },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.InsufficientEthRemaining,
- );
- });
- });
- describe('marketBuyOrdersWithEth without extra fees', () => {
- it('should buy the exact amount of makerAsset in a single order', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy the exact amount of makerAsset in multiple orders', async () => {
- const secondOrderWithoutFee = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [orderWithoutFee, secondOrderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = ordersWithoutFee[0].makerAssetAmount.plus(
- ordersWithoutFee[1].makerAssetAmount.dividedToIntegerBy(2),
- );
- const ethValue = ordersWithoutFee[0].takerAssetAmount.plus(
- ordersWithoutFee[1].takerAssetAmount.dividedToIntegerBy(2),
- );
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy the exact amount of makerAsset and return excess ETH', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount;
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue.dividedToIntegerBy(2);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy the exact amount of makerAsset and pay ZRX from feeOrders', async () => {
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithFee.takerAssetAmount;
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount.dividedToIntegerBy(2);
- const feeAmount = orderWithFee.takerFee.dividedToIntegerBy(2);
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const totalEthSpent = primaryTakerAssetFillAmount
- .plus(wethSpentOnFeeOrders)
- .plus(gasPrice.times(tx.gasUsed));
-
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy slightly greater than makerAssetAmount when buying ZRX', async () => {
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetData: assetDataUtils.encodeERC20AssetData(zrxToken.address),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithFee.takerAssetAmount;
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ForwarderWrapper.getWethForFeeOrders(
- makerAssetFillAmount,
- ordersWithFee,
- );
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- const makerAssetFilledAmount = orderWithFee.makerAssetAmount
- .times(primaryTakerAssetFillAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
- const takerFeePaid = orderWithFee.takerFee
- .times(primaryTakerAssetFillAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
- const makerFeePaid = orderWithFee.makerFee
- .times(primaryTakerAssetFillAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
- const totalZrxPurchased = makerAssetFilledAmount.minus(takerFeePaid);
- // Up to 1 wei worth of ZRX will be overbought per order
- const maxOverboughtZrx = new BigNumber(1)
- .times(orderWithFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithFee.takerAssetAmount);
-
- expect(totalZrxPurchased).to.be.bignumber.gte(makerAssetFillAmount);
- expect(totalZrxPurchased).to.be.bignumber.lte(makerAssetFillAmount.plus(maxOverboughtZrx));
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFilledAmount).minus(makerFeePaid),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(totalZrxPurchased),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[forwarderContract.address][zrxToken.address],
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(4);
- return expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- }),
- RevertReason.CompleteFillFailed,
- );
- });
- it('should buy an ERC721 asset from a single order', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = new BigNumber(1);
- const ethValue = orderWithFee.takerAssetAmount;
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- from: takerAddress,
- value: ethValue,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should revert if buying an ERC721 asset when later orders contain different makerAssetData', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- });
- const differentMakerAssetDataOrder = await orderFactory.newSignedOrderAsync();
- const ordersWithoutFee = [orderWithoutFee, differentMakerAssetDataOrder];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = new BigNumber(1).plus(differentMakerAssetDataOrder.makerAssetAmount);
- const ethValue = orderWithFee.takerAssetAmount;
- return expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- }),
- RevertReason.CompleteFillFailed,
- );
- });
- it('should buy an ERC721 asset and pay ZRX fees from a single fee order', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const feeOrders = [feeOrder];
- const makerAssetFillAmount = orderWithFee.makerAssetAmount;
- const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount;
- const feeAmount = orderWithFee.takerFee;
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const ethValue = primaryTakerAssetFillAmount.plus(wethSpentOnFeeOrders);
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed));
-
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should buy an ERC721 asset and pay ZRX fees from multiple fee orders', async () => {
- const makerAssetId = erc721MakerAssetIds[0];
- orderWithFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber(1),
- makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT),
- });
- const ordersWithFee = [orderWithFee];
- const makerAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- const makerAssetAmount = orderWithFee.takerFee.dividedToIntegerBy(2);
- const takerAssetAmount = feeOrder.takerAssetAmount
- .times(makerAssetAmount)
- .dividedToIntegerBy(feeOrder.makerAssetAmount);
-
- const firstFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const secondFeeOrder = await orderFactory.newSignedOrderAsync({
- makerAssetData,
- makerAssetAmount,
- takerAssetAmount,
- });
- const feeOrders = [firstFeeOrder, secondFeeOrder];
-
- const makerAssetFillAmount = orderWithFee.makerAssetAmount;
- const primaryTakerAssetFillAmount = orderWithFee.takerAssetAmount;
- const feeAmount = orderWithFee.takerFee;
- const wethSpentOnFeeOrders = ForwarderWrapper.getWethForFeeOrders(feeAmount, feeOrders);
- const ethValue = primaryTakerAssetFillAmount.plus(wethSpentOnFeeOrders);
-
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const totalEthSpent = ethValue.plus(gasPrice.times(tx.gasUsed));
-
- expect(newOwner).to.be.bignumber.equal(takerAddress);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount).plus(wethSpentOnFeeOrders),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded', async () => {
- // The 0x Protocol contracts round the exchange rate in favor of the Maker.
- // In this case, the taker must round up how much they're going to spend, which
- // in turn increases the amount of MakerAsset being purchased.
- // Example:
- // The taker wants to buy 5 units of the MakerAsset at a rate of 3M/2T.
- // For every 2 units of TakerAsset, the taker will receive 3 units of MakerAsset.
- // To purchase 5 units, the taker must spend 10/3 = 3.33 units of TakerAssset.
- // However, the Taker can only spend whole units.
- // Spending floor(10/3) = 3 units will yield a profit of Floor(3*3/2) = Floor(4.5) = 4 units of MakerAsset.
- // Spending ceil(10/3) = 4 units will yield a profit of Floor(4*3/2) = 6 units of MakerAsset.
- //
- // The forwarding contract will opt for the second option, which overbuys, to ensure the taker
- // receives at least the amount of MakerAsset they requested.
- //
- // Construct test case using values from example above
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('30'),
- takerAssetAmount: new BigNumber('20'),
- makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const desiredMakerAssetFillAmount = new BigNumber('5');
- const makerAssetFillAmount = new BigNumber('6');
- const ethValue = new BigNumber('4');
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX', async () => {
- // See the test case above for a detailed description of this case.
- // The difference here is that the MakerAsset is ZRX. We expect the same result as above,
- // but this tests a different code path.
- //
- // Construct test case using values from example above
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('30'),
- takerAssetAmount: new BigNumber('20'),
- makerAssetData: zrxAssetData,
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const desiredMakerAssetFillAmount = new BigNumber('5');
- const makerAssetFillAmount = new BigNumber('6');
- const ethValue = new BigNumber('4');
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => {
- // Order taken from a transaction on mainnet that failed due to a rounding error.
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('268166666666666666666'),
- takerAssetAmount: new BigNumber('219090625878836371'),
- makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- // The taker will receive more than the desired amount of makerAsset due to rounding
- const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000');
- const ethValue = new BigNumber('4084971271824171');
- const makerAssetFillAmount = ethValue
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX (Regression Test)', async () => {
- // Order taken from a transaction on mainnet that failed due to a rounding error.
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('268166666666666666666'),
- takerAssetAmount: new BigNumber('219090625878836371'),
- makerAssetData: zrxAssetData,
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- // The taker will receive more than the desired amount of makerAsset due to rounding
- const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000');
- const ethValue = new BigNumber('4084971271824171');
- const makerAssetFillAmount = ethValue
- .times(orderWithoutFee.makerAssetAmount)
- .dividedToIntegerBy(orderWithoutFee.takerAssetAmount);
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- desiredMakerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- );
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('Should buy correct MakerAsset when exchange rate is NOT rounded, and MakerAsset is ZRX (Regression Test)', async () => {
- // An extra unit of TakerAsset was sent to the exchange contract to account for rounding errors, in Forwarder v1.
- // Specifically, the takerFillAmount was calculated using Floor(desiredMakerAmount * exchangeRate) + 1
- // We have since changed this to be Ceil(desiredMakerAmount * exchangeRate)
- // These calculations produce different results when `desiredMakerAmount * exchangeRate` is an integer.
- //
- // This test verifies that `ceil` is sufficient:
- // Let TakerAssetAmount = MakerAssetAmount * 2
- // -> exchangeRate = TakerAssetAmount / MakerAssetAmount = (2*MakerAssetAmount)/MakerAssetAmount = 2
- // .: desiredMakerAmount * exchangeRate is an integer.
- //
- // Construct test case using values from example above
- orderWithoutFee = await orderFactory.newSignedOrderAsync({
- makerAssetAmount: new BigNumber('30'),
- takerAssetAmount: new BigNumber('60'),
- makerAssetData: zrxAssetData,
- takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address),
- makerFee: new BigNumber(0),
- takerFee: new BigNumber(0),
- });
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = new BigNumber('5');
- const ethValue = new BigNumber('10');
- // Execute test case
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, {
- value: ethValue,
- from: takerAddress,
- });
- // Fetch end balances and construct expected outputs
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const newBalances = await erc20Wrapper.getBalancesAsync();
- const primaryTakerAssetFillAmount = ethValue;
- const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
- // Validate test case
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- });
- describe('marketBuyOrdersWithEth with extra fees', () => {
- it('should buy an asset and send fee to feeRecipient', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount;
-
- const baseFeePercentage = 2;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- makerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- );
- const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
- const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
- const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipientAddress);
- const newBalances = await erc20Wrapper.getBalancesAsync();
-
- const primaryTakerAssetFillAmount = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
- const ethSpentOnFee = ForwarderWrapper.getPercentageOfValue(primaryTakerAssetFillAmount, baseFeePercentage);
- const totalEthSpent = primaryTakerAssetFillAmount.plus(ethSpentOnFee).plus(gasPrice.times(tx.gasUsed));
-
- expect(feeRecipientEthBalanceAfter).to.be.bignumber.equal(feeRecipientEthBalanceBefore.plus(ethSpentOnFee));
- expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
- expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
- );
- expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
- erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
- );
- expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal(
- erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount),
- );
- expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal(
- constants.ZERO_AMOUNT,
- );
- expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should fail if the fee is set too high', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount;
-
- const baseFeePercentage = 6;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- await expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- makerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.FeePercentageTooLarge,
- );
- });
- it('should fail if there is not enough ETH remaining to pay the fee', async () => {
- const ordersWithoutFee = [orderWithoutFee];
- const feeOrders: SignedOrder[] = [];
- const makerAssetFillAmount = orderWithoutFee.makerAssetAmount.dividedToIntegerBy(2);
- const ethValue = orderWithoutFee.takerAssetAmount.dividedToIntegerBy(2);
-
- const baseFeePercentage = 2;
- feePercentage = ForwarderWrapper.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, baseFeePercentage);
- await expectTransactionFailedAsync(
- forwarderWrapper.marketBuyOrdersWithEthAsync(
- ordersWithoutFee,
- feeOrders,
- makerAssetFillAmount,
- {
- value: ethValue,
- from: takerAddress,
- },
- { feePercentage, feeRecipient: feeRecipientAddress },
- ),
- RevertReason.InsufficientEthRemaining,
- );
- });
- });
- describe('withdrawAsset', () => {
- it('should allow owner to withdraw ERC20 tokens', async () => {
- const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address];
- await forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: owner });
- const newBalances = await erc20Wrapper.getBalancesAsync();
- expect(newBalances[owner][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[owner][zrxToken.address].plus(zrxWithdrawAmount),
- );
- expect(newBalances[forwarderContract.address][zrxToken.address]).to.be.bignumber.equal(
- erc20Balances[forwarderContract.address][zrxToken.address].minus(zrxWithdrawAmount),
- );
- });
- it('should revert if not called by owner', async () => {
- const zrxWithdrawAmount = erc20Balances[forwarderContract.address][zrxToken.address];
- await expectTransactionFailedAsync(
- forwarderWrapper.withdrawAssetAsync(zrxAssetData, zrxWithdrawAmount, { from: makerAddress }),
- RevertReason.OnlyContractOwner,
- );
- });
- });
-});
-// tslint:disable:max-file-line-count
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/extensions/order_validator.ts b/packages/contracts/test/extensions/order_validator.ts
deleted file mode 100644
index 37d7c4c5a..000000000
--- a/packages/contracts/test/extensions/order_validator.ts
+++ /dev/null
@@ -1,603 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
-import { artifacts } from '../../src/artifacts';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { ERC20Wrapper } from '../utils/erc20_wrapper';
-import { ERC721Wrapper } from '../utils/erc721_wrapper';
-import { ExchangeWrapper } from '../utils/exchange_wrapper';
-import { OrderFactory } from '../utils/order_factory';
-import { OrderStatus } from '../utils/types';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('OrderValidator', () => {
- let makerAddress: string;
- let owner: string;
- let takerAddress: string;
- let erc20AssetData: string;
- let erc721AssetData: string;
-
- let erc20Token: DummyERC20TokenContract;
- let zrxToken: DummyERC20TokenContract;
- let erc721Token: DummyERC721TokenContract;
- let exchange: ExchangeContract;
- let orderValidator: OrderValidatorContract;
- let erc20Proxy: ERC20ProxyContract;
- let erc721Proxy: ERC721ProxyContract;
-
- let signedOrder: SignedOrder;
- let signedOrder2: SignedOrder;
- let orderFactory: OrderFactory;
-
- const tokenId = new BigNumber(123456789);
- const tokenId2 = new BigNumber(987654321);
- const ERC721_BALANCE = new BigNumber(1);
- const ERC721_ALLOWANCE = new BigNumber(1);
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const usedAddresses = ([owner, makerAddress, takerAddress] = _.slice(accounts, 0, 3));
-
- const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
- const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
-
- const numDummyErc20ToDeploy = 2;
- [erc20Token, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
- numDummyErc20ToDeploy,
- constants.DUMMY_TOKEN_DECIMALS,
- );
- erc20Proxy = await erc20Wrapper.deployProxyAsync();
-
- [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- erc721Proxy = await erc721Wrapper.deployProxyAsync();
-
- const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
- exchange = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- const exchangeWrapper = new ExchangeWrapper(exchange, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
-
- orderValidator = await OrderValidatorContract.deployFrom0xArtifactAsync(
- artifacts.OrderValidator,
- provider,
- txDefaults,
- exchange.address,
- zrxAssetData,
- );
-
- erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
- erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
- const defaultOrderParams = {
- ...constants.STATIC_ORDER_PARAMS,
- exchangeAddress: exchange.address,
- makerAddress,
- feeRecipientAddress: constants.NULL_ADDRESS,
- makerAssetData: erc20AssetData,
- takerAssetData: erc721AssetData,
- };
- const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
- orderFactory = new OrderFactory(privateKey, defaultOrderParams);
- });
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('getBalanceAndAllowance', () => {
- describe('getERC721TokenOwner', async () => {
- it('should return the null address when tokenId is not owned', async () => {
- const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(makerAddress, tokenId);
- expect(tokenOwner).to.be.equal(constants.NULL_ADDRESS);
- });
- it('should return the owner address when tokenId is owned', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(erc721Token.address, tokenId);
- expect(tokenOwner).to.be.equal(makerAddress);
- });
- });
- describe('ERC20 assetData', () => {
- it('should return the correct balances and allowances when both values are 0', async () => {
- const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc20AssetData,
- );
- expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newBalance);
- expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newAllowance);
- });
- it('should return the correct balance and allowance when both values are non-zero', async () => {
- const balance = new BigNumber(123);
- const allowance = new BigNumber(456);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc20AssetData,
- );
- expect(balance).to.be.bignumber.equal(newBalance);
- expect(allowance).to.be.bignumber.equal(newAllowance);
- });
- });
- describe('ERC721 assetData', () => {
- it('should return a balance of 0 when the tokenId is not owned by target', async () => {
- const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return an allowance of 0 when no approval is set', async () => {
- const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return a balance of 1 when the tokenId is owned by target', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newBalance).to.be.bignumber.equal(ERC721_BALANCE);
- });
- it('should return an allowance of 1 when ERC721Proxy is approved for all', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- });
- it('should return an allowance of 0 when ERC721Proxy is approved for specific tokenId', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
- makerAddress,
- erc721AssetData,
- );
- expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- });
- });
- describe('getBalancesAndAllowances', () => {
- it('should return the correct balances and allowances when all values are 0', async () => {
- const [
- [erc20Balance, erc721Balance],
- [erc20Allowance, erc721Allowance],
- ] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [
- erc20AssetData,
- erc721AssetData,
- ]);
- expect(erc20Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(erc721Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(erc20Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(erc721Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return the correct balances and allowances when balances and allowances are non-zero', async () => {
- const balance = new BigNumber(123);
- const allowance = new BigNumber(456);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [
- [erc20Balance, erc721Balance],
- [erc20Allowance, erc721Allowance],
- ] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [
- erc20AssetData,
- erc721AssetData,
- ]);
- expect(erc20Balance).to.be.bignumber.equal(balance);
- expect(erc721Balance).to.be.bignumber.equal(ERC721_BALANCE);
- expect(erc20Allowance).to.be.bignumber.equal(allowance);
- expect(erc721Allowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- });
- });
- describe('getTraderInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should return the correct info when no balances or allowances are set', async () => {
- const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress);
- expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return the correct info when balances and allowances are set', async () => {
- const makerBalance = new BigNumber(123);
- const makerAllowance = new BigNumber(456);
- const makerZrxBalance = new BigNumber(789);
- const takerZrxAllowance = new BigNumber(987);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress);
- expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance);
- expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance);
- expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
- expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
- expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
- });
- });
- describe('getTradersInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- signedOrder2 = await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2),
- });
- });
- it('should return the correct info when no balances or allowances have been set', async () => {
- const orders = [signedOrder, signedOrder2];
- const takers = [takerAddress, takerAddress];
- const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers);
- expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return the correct info when balances and allowances are set', async () => {
- const makerBalance = new BigNumber(123);
- const makerAllowance = new BigNumber(456);
- const makerZrxBalance = new BigNumber(789);
- const takerZrxAllowance = new BigNumber(987);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const orders = [signedOrder, signedOrder2];
- const takers = [takerAddress, takerAddress];
- const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers);
-
- expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance);
- expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance);
- expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
- expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
- expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance);
- expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance);
- expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
- expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
- expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
- });
- });
- describe('getOrderAndTraderInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- });
- it('should return the correct info when no balances or allowances are set', async () => {
- const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync(
- signedOrder,
- takerAddress,
- );
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return the correct info when balances and allowances are set', async () => {
- const makerBalance = new BigNumber(123);
- const makerAllowance = new BigNumber(456);
- const makerZrxBalance = new BigNumber(789);
- const takerZrxAllowance = new BigNumber(987);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync(
- signedOrder,
- takerAddress,
- );
- const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
- expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
- expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
- expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance);
- expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance);
- expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
- expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
- expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
- });
- });
- describe('getOrdersAndTradersInfo', () => {
- beforeEach(async () => {
- signedOrder = await orderFactory.newSignedOrderAsync();
- signedOrder2 = await orderFactory.newSignedOrderAsync({
- takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2),
- });
- });
- it('should return the correct info when no balances or allowances have been set', async () => {
- const orders = [signedOrder, signedOrder2];
- const takers = [takerAddress, takerAddress];
- const [
- [orderInfo1, orderInfo2],
- [traderInfo1, traderInfo2],
- ] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers);
- const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
- expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.FILLABLE);
- expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1);
- expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.FILLABLE);
- expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2);
- expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- });
- it('should return the correct info when balances and allowances are set', async () => {
- const makerBalance = new BigNumber(123);
- const makerAllowance = new BigNumber(456);
- const makerZrxBalance = new BigNumber(789);
- const takerZrxAllowance = new BigNumber(987);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
- from: makerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
- from: takerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const orders = [signedOrder, signedOrder2];
- const takers = [takerAddress, takerAddress];
- const [
- [orderInfo1, orderInfo2],
- [traderInfo1, traderInfo2],
- ] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers);
- const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder);
- const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
- expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.FILLABLE);
- expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1);
- expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.FILLABLE);
- expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2);
- expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance);
- expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance);
- expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
- expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
- expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance);
- expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance);
- expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
- expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
- expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
- expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
- expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
- });
- });
-});
-// tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/global_hooks.ts b/packages/contracts/test/global_hooks.ts
deleted file mode 100644
index 2e9ac9e21..000000000
--- a/packages/contracts/test/global_hooks.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { env, EnvVars } from '@0x/dev-utils';
-
-import { coverage } from './utils/coverage';
-import { profiler } from './utils/profiler';
-
-after('generate coverage report', async () => {
- if (env.parseBoolean(EnvVars.SolidityCoverage)) {
- const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
- await coverageSubprovider.writeCoverageAsync();
- }
- if (env.parseBoolean(EnvVars.SolidityProfiler)) {
- const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
- await profilerSubprovider.writeProfilerOutputAsync();
- }
-});
diff --git a/packages/contracts/test/libraries/lib_bytes.ts b/packages/contracts/test/libraries/lib_bytes.ts
deleted file mode 100644
index b1a389f00..000000000
--- a/packages/contracts/test/libraries/lib_bytes.ts
+++ /dev/null
@@ -1,871 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import BN = require('bn.js');
-import * as chai from 'chai';
-import ethUtil = require('ethereumjs-util');
-import * as _ from 'lodash';
-
-import { TestLibBytesContract } from '../../generated-wrappers/test_lib_bytes';
-import { artifacts } from '../../src/artifacts';
-import { expectContractCallFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { typeEncodingUtils } from '../utils/type_encoding_utils';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-// BUG: Ideally we would use Buffer.from(memory).toString('hex')
-// https://github.com/Microsoft/TypeScript/issues/23155
-const toHex = (buf: Uint8Array): string => buf.reduce((a, v) => a + ('00' + v.toString(16)).slice(-2), '0x');
-
-const fromHex = (str: string): Uint8Array => Uint8Array.from(Buffer.from(str.slice(2), 'hex'));
-
-describe('LibBytes', () => {
- let libBytes: TestLibBytesContract;
- const byteArrayShorterThan32Bytes = '0x012345';
- const byteArrayShorterThan20Bytes = byteArrayShorterThan32Bytes;
- const byteArrayLongerThan32Bytes =
- '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
- const byteArrayLongerThan32BytesFirstBytesSwapped =
- '0x2301456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
- const byteArrayLongerThan32BytesLastBytesSwapped =
- '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abefcd';
- let testAddress: string;
- let testAddressB: string;
- const testBytes32 = '0x102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f01020';
- const testBytes32B = '0x534877abd8443578526845cdfef020047528759477fedef87346527659aced32';
- const testUint256 = new BigNumber(testBytes32, 16);
- const testUint256B = new BigNumber(testBytes32B, 16);
- const testBytes4 = '0xabcdef12';
- const testByte = '0xab';
- let shortData: string;
- let shortTestBytes: string;
- let shortTestBytesAsBuffer: Buffer;
- let wordOfData: string;
- let wordOfTestBytes: string;
- let wordOfTestBytesAsBuffer: Buffer;
- let longData: string;
- let longTestBytes: string;
- let longTestBytesAsBuffer: Buffer;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- // Setup accounts & addresses
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- testAddress = accounts[1];
- testAddressB = accounts[2];
- // Deploy LibBytes
- libBytes = await TestLibBytesContract.deployFrom0xArtifactAsync(artifacts.TestLibBytes, provider, txDefaults);
- // Verify lengths of test data
- const byteArrayShorterThan32BytesLength = ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength;
- expect(byteArrayShorterThan32BytesLength).to.be.lessThan(32);
- const byteArrayLongerThan32BytesLength = ethUtil.toBuffer(byteArrayLongerThan32Bytes).byteLength;
- expect(byteArrayLongerThan32BytesLength).to.be.greaterThan(32);
- const testBytes32Length = ethUtil.toBuffer(testBytes32).byteLength;
- expect(testBytes32Length).to.be.equal(32);
- // Create short test bytes
- shortData = '0xffffaa';
- const encodedShortData = ethUtil.toBuffer(shortData);
- const shortDataLength = new BigNumber(encodedShortData.byteLength);
- const encodedShortDataLength = typeEncodingUtils.encodeUint256(shortDataLength);
- shortTestBytesAsBuffer = Buffer.concat([encodedShortDataLength, encodedShortData]);
- shortTestBytes = ethUtil.bufferToHex(shortTestBytesAsBuffer);
- // Create test bytes one word in length
- wordOfData = ethUtil.bufferToHex(typeEncodingUtils.encodeUint256(generatePseudoRandomSalt()));
- const encodedWordOfData = ethUtil.toBuffer(wordOfData);
- const wordOfDataLength = new BigNumber(encodedWordOfData.byteLength);
- const encodedWordOfDataLength = typeEncodingUtils.encodeUint256(wordOfDataLength);
- wordOfTestBytesAsBuffer = Buffer.concat([encodedWordOfDataLength, encodedWordOfData]);
- wordOfTestBytes = ethUtil.bufferToHex(wordOfTestBytesAsBuffer);
- // Create long test bytes (combines short test bytes with word of test bytes)
- longData = ethUtil.bufferToHex(Buffer.concat([encodedShortData, encodedWordOfData]));
- const longDataLength = new BigNumber(encodedShortData.byteLength + encodedWordOfData.byteLength);
- const encodedLongDataLength = typeEncodingUtils.encodeUint256(longDataLength);
- longTestBytesAsBuffer = Buffer.concat([encodedLongDataLength, encodedShortData, encodedWordOfData]);
- longTestBytes = ethUtil.bufferToHex(longTestBytesAsBuffer);
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('popLastByte', () => {
- it('should revert if length is 0', async () => {
- return expectContractCallFailedAsync(
- libBytes.publicPopLastByte.callAsync(constants.NULL_BYTES),
- RevertReason.LibBytesGreaterThanZeroLengthRequired,
- );
- });
- it('should pop the last byte from the input and return it when array holds more than 1 byte', async () => {
- const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(byteArrayLongerThan32Bytes);
- const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -2);
- const expectedPoppedByte = `0x${byteArrayLongerThan32Bytes.slice(-2)}`;
- expect(newBytes).to.equal(expectedNewBytes);
- expect(poppedByte).to.equal(expectedPoppedByte);
- });
- it('should pop the last byte from the input and return it when array is exactly 1 byte', async () => {
- const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(testByte);
- const expectedNewBytes = '0x';
- expect(newBytes).to.equal(expectedNewBytes);
- return expect(poppedByte).to.be.equal(testByte);
- });
- });
-
- describe('popLast20Bytes', () => {
- it('should revert if length is less than 20', async () => {
- return expectContractCallFailedAsync(
- libBytes.publicPopLast20Bytes.callAsync(byteArrayShorterThan20Bytes),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- it('should pop the last 20 bytes from the input and return it when array holds more than 20 bytes', async () => {
- const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(byteArrayLongerThan32Bytes);
- const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -40);
- const expectedPoppedAddress = `0x${byteArrayLongerThan32Bytes.slice(-40)}`;
- expect(newBytes).to.equal(expectedNewBytes);
- expect(poppedAddress).to.equal(expectedPoppedAddress);
- });
- it('should pop the last 20 bytes from the input and return it when array is exactly 20 bytes', async () => {
- const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(testAddress);
- const expectedNewBytes = '0x';
- const expectedPoppedAddress = testAddress;
- expect(newBytes).to.equal(expectedNewBytes);
- expect(poppedAddress).to.equal(expectedPoppedAddress);
- });
- });
-
- describe('equals', () => {
- it('should return true if byte arrays are equal (both arrays < 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayShorterThan32Bytes,
- byteArrayShorterThan32Bytes,
- );
- return expect(isEqual).to.be.true();
- });
- it('should return true if byte arrays are equal (both arrays > 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.true();
- });
- it('should return false if byte arrays are not equal (first array < 32 bytes, second array > 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayShorterThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
- it('should return false if byte arrays are not equal (first array > 32 bytes, second array < 32 bytes)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32Bytes,
- byteArrayShorterThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
- it('should return false if byte arrays are not equal (same length, but a byte in first word differs)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32BytesFirstBytesSwapped,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
- it('should return false if byte arrays are not equal (same length, but a byte in last word differs)', async () => {
- const isEqual = await libBytes.publicEquals.callAsync(
- byteArrayLongerThan32BytesLastBytesSwapped,
- byteArrayLongerThan32Bytes,
- );
- return expect(isEqual).to.be.false();
- });
-
- describe('should ignore trailing data', () => {
- it('should return true when both < 32 bytes', async () => {
- const isEqual = await libBytes.publicEqualsPop1.callAsync('0x0102', '0x0103');
- return expect(isEqual).to.be.true();
- });
- });
- });
-
- describe('deepCopyBytes', () => {
- it('should revert if dest is shorter than source', async () => {
- return expectContractCallFailedAsync(
- libBytes.publicDeepCopyBytes.callAsync(byteArrayShorterThan32Bytes, byteArrayLongerThan32Bytes),
- RevertReason.LibBytesGreaterOrEqualToSourceBytesLengthRequired,
- );
- });
- it('should overwrite dest with source if source and dest have equal length', async () => {
- const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length - 2)}`;
- const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
- zeroedByteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- return expect(zeroedBytesAfterCopy).to.be.equal(byteArrayLongerThan32Bytes);
- });
- it('should overwrite the leftmost len(source) bytes of dest if dest is larger than source', async () => {
- const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`;
- const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
- zeroedByteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- const copiedBytes = zeroedBytesAfterCopy.slice(0, byteArrayLongerThan32Bytes.length);
- return expect(copiedBytes).to.be.equal(byteArrayLongerThan32Bytes);
- });
- it('should not overwrite the rightmost bytes of dest if dest is larger than source', async () => {
- const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`;
- const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
- zeroedByteArrayLongerThan32Bytes,
- byteArrayLongerThan32Bytes,
- );
- const expectedNotCopiedBytes = zeroedByteArrayLongerThan32Bytes.slice(byteArrayLongerThan32Bytes.length);
- const notCopiedBytes = zeroedBytesAfterCopy.slice(byteArrayLongerThan32Bytes.length);
- return expect(notCopiedBytes).to.be.equal(expectedNotCopiedBytes);
- });
- });
-
- describe('readAddress', () => {
- it('should successfully read address when the address takes up the whole array', async () => {
- const byteArray = ethUtil.addHexPrefix(testAddress);
- const testAddressOffset = new BigNumber(0);
- const address = await libBytes.publicReadAddress.callAsync(byteArray, testAddressOffset);
- return expect(address).to.be.equal(testAddress);
- });
- it('should successfully read address when it is offset in the array', async () => {
- const addressByteArrayBuffer = ethUtil.toBuffer(testAddress);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const address = await libBytes.publicReadAddress.callAsync(combinedByteArray, testAddressOffset);
- return expect(address).to.be.equal(testAddress);
- });
- it('should fail if the byte array is too short to hold an address', async () => {
- const shortByteArray = '0xabcdef';
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadAddress.callAsync(shortByteArray, offset),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
- const byteArray = testAddress;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadAddress.callAsync(byteArray, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- });
-
- describe('writeAddress', () => {
- it('should successfully write address when the address takes up the whole array', async () => {
- const byteArray = testAddress;
- const testAddressOffset = new BigNumber(0);
- const newByteArray = await libBytes.publicWriteAddress.callAsync(
- byteArray,
- testAddressOffset,
- testAddressB,
- );
- return expect(newByteArray).to.be.equal(testAddressB);
- });
- it('should successfully write address when it is offset in the array', async () => {
- const addressByteArrayBuffer = ethUtil.toBuffer(testAddress);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const newByteArray = await libBytes.publicWriteAddress.callAsync(
- combinedByteArray,
- testAddressOffset,
- testAddressB,
- );
- const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
- const addressFromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
- const addressFromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(addressFromOffsetBuffer));
- return expect(addressFromOffset).to.be.equal(testAddressB);
- });
- it('should fail if the byte array is too short to hold an address', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicWriteAddress.callAsync(byteArrayShorterThan20Bytes, offset, testAddress),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
- const byteArray = byteArrayLongerThan32Bytes;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteAddress.callAsync(byteArray, badOffset, testAddress),
- RevertReason.LibBytesGreaterOrEqualTo20LengthRequired,
- );
- });
- });
-
- describe('readBytes32', () => {
- it('should successfully read bytes32 when the bytes32 takes up the whole array', async () => {
- const testBytes32Offset = new BigNumber(0);
- const bytes32 = await libBytes.publicReadBytes32.callAsync(testBytes32, testBytes32Offset);
- return expect(bytes32).to.be.equal(testBytes32);
- });
- it('should successfully read bytes32 when it is offset in the array', async () => {
- const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes32 = await libBytes.publicReadBytes32.callAsync(combinedByteArray, testBytes32Offset);
- return expect(bytes32).to.be.equal(testBytes32);
- });
- it('should fail if the byte array is too short to hold a bytes32', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes32.callAsync(testBytes32, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('writeBytes32', () => {
- it('should successfully write bytes32 when the address takes up the whole array', async () => {
- const byteArray = testBytes32;
- const testBytes32Offset = new BigNumber(0);
- const newByteArray = await libBytes.publicWriteBytes32.callAsync(
- byteArray,
- testBytes32Offset,
- testBytes32B,
- );
- return expect(newByteArray).to.be.equal(testBytes32B);
- });
- it('should successfully write bytes32 when it is offset in the array', async () => {
- const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const newByteArray = await libBytes.publicWriteBytes32.callAsync(
- combinedByteArray,
- testBytes32Offset,
- testBytes32B,
- );
- const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
- const bytes32FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
- const bytes32FromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(bytes32FromOffsetBuffer));
- return expect(bytes32FromOffset).to.be.equal(testBytes32B);
- });
- it('should fail if the byte array is too short to hold a bytes32', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytes32.callAsync(byteArrayShorterThan32Bytes, offset, testBytes32),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
- const byteArray = byteArrayLongerThan32Bytes;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytes32.callAsync(byteArray, badOffset, testBytes32),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('readUint256', () => {
- it('should successfully read uint256 when the uint256 takes up the whole array', async () => {
- const formattedTestUint256 = new BN(testUint256.toString(10));
- const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
- const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
- const testUint256Offset = new BigNumber(0);
- const uint256 = await libBytes.publicReadUint256.callAsync(byteArray, testUint256Offset);
- return expect(uint256).to.bignumber.equal(testUint256);
- });
- it('should successfully read uint256 when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const formattedTestUint256 = new BN(testUint256.toString(10));
- const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, testUint256AsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const uint256 = await libBytes.publicReadUint256.callAsync(combinedByteArray, testUint256Offset);
- return expect(uint256).to.bignumber.equal(testUint256);
- });
- it('should fail if the byte array is too short to hold a uint256', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
- const formattedTestUint256 = new BN(testUint256.toString(10));
- const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
- const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
- const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadUint256.callAsync(byteArray, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('writeUint256', () => {
- it('should successfully write uint256 when the address takes up the whole array', async () => {
- const byteArray = testBytes32;
- const testUint256Offset = new BigNumber(0);
- const newByteArray = await libBytes.publicWriteUint256.callAsync(
- byteArray,
- testUint256Offset,
- testUint256B,
- );
- const newByteArrayAsUint256 = new BigNumber(newByteArray, 16);
- return expect(newByteArrayAsUint256).to.be.bignumber.equal(testUint256B);
- });
- it('should successfully write uint256 when it is offset in the array', async () => {
- const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const newByteArray = await libBytes.publicWriteUint256.callAsync(
- combinedByteArray,
- testUint256Offset,
- testUint256B,
- );
- const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
- const uint256FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
- const uint256FromOffset = new BigNumber(
- ethUtil.addHexPrefix(ethUtil.bufferToHex(uint256FromOffsetBuffer)),
- 16,
- );
- return expect(uint256FromOffset).to.be.bignumber.equal(testUint256B);
- });
- it('should fail if the byte array is too short to hold a uint256', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicWriteUint256.callAsync(byteArrayShorterThan32Bytes, offset, testUint256),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
- const byteArray = byteArrayLongerThan32Bytes;
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteUint256.callAsync(byteArray, badOffset, testUint256),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('readBytes4', () => {
- // AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0'
- it('should revert if byte array has a length < 4', async () => {
- const byteArrayLessThan4Bytes = '0x010101';
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes4.callAsync(byteArrayLessThan4Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
- );
- });
- it('should return the first 4 bytes of a byte array of arbitrary length', async () => {
- const first4Bytes = await libBytes.publicReadBytes4.callAsync(byteArrayLongerThan32Bytes, new BigNumber(0));
- const expectedFirst4Bytes = byteArrayLongerThan32Bytes.slice(0, 10);
- expect(first4Bytes).to.equal(expectedFirst4Bytes);
- });
- it('should successfully read bytes4 when the bytes4 takes up the whole array', async () => {
- const testBytes4Offset = new BigNumber(0);
- const bytes4 = await libBytes.publicReadBytes4.callAsync(testBytes4, testBytes4Offset);
- return expect(bytes4).to.be.equal(testBytes4);
- });
- it('should successfully read bytes4 when it is offset in the array', async () => {
- const bytes4ByteArrayBuffer = ethUtil.toBuffer(testBytes4);
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes4ByteArrayBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testBytes4Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes4 = await libBytes.publicReadBytes4.callAsync(combinedByteArray, testBytes4Offset);
- return expect(bytes4).to.be.equal(testBytes4);
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold a bytes4', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(testBytes4).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytes4.callAsync(testBytes4, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
- );
- });
- });
-
- describe('readBytesWithLength', () => {
- it('should successfully read short, nested array of bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(shortTestBytes, testBytesOffset);
- return expect(bytes).to.be.equal(shortData);
- });
- it('should successfully read short, nested array of bytes when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, shortTestBytesAsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset);
- return expect(bytes).to.be.equal(shortData);
- });
- it('should successfully read a nested array of bytes - one word in length - when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(wordOfTestBytes, testBytesOffset);
- return expect(bytes).to.be.equal(wordOfData);
- });
- it('should successfully read a nested array of bytes - one word in length - when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, wordOfTestBytesAsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset);
- return expect(bytes).to.be.equal(wordOfData);
- });
- it('should successfully read long, nested array of bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(longTestBytes, testBytesOffset);
- return expect(bytes).to.be.equal(longData);
- });
- it('should successfully read long, nested array of bytes when it is offset in the array', async () => {
- const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
- const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, longTestBytesAsBuffer]);
- const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
- const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(combinedByteArray, testUint256Offset);
- return expect(bytes).to.be.equal(longData);
- });
- it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
- // The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read.
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, offset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if we store a nested byte array length, without a nested byte array', async () => {
- const offset = new BigNumber(0);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(testBytes32, offset),
- RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(byteArrayShorterThan32Bytes, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => {
- const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicReadBytesWithLength.callAsync(testBytes32, badOffset),
- RevertReason.LibBytesGreaterOrEqualTo32LengthRequired,
- );
- });
- });
-
- describe('writeBytesWithLength', () => {
- it('should successfully write short, nested array of bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
- const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- testBytesOffset,
- shortData,
- );
- const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytesRead).to.be.equal(shortData);
- });
- it('should successfully write short, nested array of bytes when it is offset in the array', async () => {
- // Write a prefix to the array
- const prefixData = '0xabcdef';
- const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
- const prefixOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(
- new Buffer(prefixDataAsBuffer.byteLength + shortTestBytesAsBuffer.byteLength),
- );
- let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- prefixOffset,
- prefixData,
- );
- // Write data after prefix
- const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
- bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- bytesWritten,
- testBytesOffset,
- shortData,
- );
- // Read data after prefix and validate
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytes).to.be.equal(shortData);
- });
- it('should successfully write a nested array of bytes - one word in length - when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(wordOfTestBytesAsBuffer.byteLength));
- const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- testBytesOffset,
- wordOfData,
- );
- const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytesRead).to.be.equal(wordOfData);
- });
- it('should successfully write a nested array of bytes - one word in length - when it is offset in the array', async () => {
- // Write a prefix to the array
- const prefixData = '0xabcdef';
- const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
- const prefixOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(
- new Buffer(prefixDataAsBuffer.byteLength + wordOfTestBytesAsBuffer.byteLength),
- );
- let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- prefixOffset,
- prefixData,
- );
- // Write data after prefix
- const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
- bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- bytesWritten,
- testBytesOffset,
- wordOfData,
- );
- // Read data after prefix and validate
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytes).to.be.equal(wordOfData);
- });
- it('should successfully write a long, nested bytes when it takes up the whole array', async () => {
- const testBytesOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(longTestBytesAsBuffer.byteLength));
- const bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- testBytesOffset,
- longData,
- );
- const bytesRead = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytesRead).to.be.equal(longData);
- });
- it('should successfully write long, nested array of bytes when it is offset in the array', async () => {
- // Write a prefix to the array
- const prefixData = '0xabcdef';
- const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
- const prefixOffset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(
- new Buffer(prefixDataAsBuffer.byteLength + longTestBytesAsBuffer.byteLength),
- );
- let bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(
- emptyByteArray,
- prefixOffset,
- prefixData,
- );
- // Write data after prefix
- const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
- bytesWritten = await libBytes.publicWriteBytesWithLength.callAsync(bytesWritten, testBytesOffset, longData);
- // Read data after prefix and validate
- const bytes = await libBytes.publicReadBytesWithLength.callAsync(bytesWritten, testBytesOffset);
- return expect(bytes).to.be.equal(longData);
- });
- it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
- const offset = new BigNumber(0);
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(1));
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, offset, longData),
- RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
- );
- });
- it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
- const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
- const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength);
- return expectContractCallFailedAsync(
- libBytes.publicWriteBytesWithLength.callAsync(emptyByteArray, badOffset, shortData),
- RevertReason.LibBytesGreaterOrEqualToNestedBytesLengthRequired,
- );
- });
- });
-
- describe('memCopy', () => {
- // Create memory 0x000102...FF
- const memSize = 256;
- // tslint:disable:no-shadowed-variable
- const memory = new Uint8Array(memSize).map((_, i) => i);
- const memHex = toHex(memory);
-
- // Reference implementation to test against
- const refMemcpy = (mem: Uint8Array, dest: number, source: number, length: number): Uint8Array =>
- Uint8Array.from(mem).copyWithin(dest, source, source + length);
-
- // Test vectors: destination, source, length, job description
- type Tests = Array<[number, number, number, string]>;
-
- const test = (tests: Tests) =>
- tests.forEach(([dest, source, length, job]) =>
- it(job, async () => {
- const expected = refMemcpy(memory, dest, source, length);
- const resultStr = await libBytes.testMemcpy.callAsync(
- memHex,
- new BigNumber(dest),
- new BigNumber(source),
- new BigNumber(length),
- );
- const result = fromHex(resultStr);
- expect(result).to.deep.equal(expected);
- }),
- );
-
- test([[0, 0, 0, 'copies zero bytes with overlap']]);
-
- describe('copies forward', () =>
- test([
- [128, 0, 0, 'zero bytes'],
- [128, 0, 1, 'one byte'],
- [128, 0, 11, 'eleven bytes'],
- [128, 0, 31, 'thirty-one bytes'],
- [128, 0, 32, 'one word'],
- [128, 0, 64, 'two words'],
- [128, 0, 96, 'three words'],
- [128, 0, 33, 'one word and one byte'],
- [128, 0, 72, 'two words and eight bytes'],
- [128, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward within one word', () =>
- test([
- [16, 0, 0, 'zero bytes'],
- [16, 0, 1, 'one byte'],
- [16, 0, 11, 'eleven bytes'],
- [16, 0, 16, 'sixteen bytes'],
- ]));
-
- describe('copies forward with one byte overlap', () =>
- test([
- [0, 0, 1, 'one byte'],
- [10, 0, 11, 'eleven bytes'],
- [30, 0, 31, 'thirty-one bytes'],
- [31, 0, 32, 'one word'],
- [32, 0, 33, 'one word and one byte'],
- [71, 0, 72, 'two words and eight bytes'],
- [99, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with thirty-one bytes overlap', () =>
- test([
- [0, 0, 31, 'thirty-one bytes'],
- [1, 0, 32, 'one word'],
- [2, 0, 33, 'one word and one byte'],
- [41, 0, 72, 'two words and eight bytes'],
- [69, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with one word overlap', () =>
- test([
- [0, 0, 32, 'one word'],
- [1, 0, 33, 'one word and one byte'],
- [41, 0, 72, 'two words and eight bytes'],
- [69, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with one word and one byte overlap', () =>
- test([
- [0, 0, 33, 'one word and one byte'],
- [40, 0, 72, 'two words and eight bytes'],
- [68, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward with two words overlap', () =>
- test([
- [0, 0, 64, 'two words'],
- [8, 0, 72, 'two words and eight bytes'],
- [36, 0, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward within one word and one byte overlap', () =>
- test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']]));
-
- describe('copies backward', () =>
- test([
- [0, 128, 0, 'zero bytes'],
- [0, 128, 1, 'one byte'],
- [0, 128, 11, 'eleven bytes'],
- [0, 128, 31, 'thirty-one bytes'],
- [0, 128, 32, 'one word'],
- [0, 128, 64, 'two words'],
- [0, 128, 96, 'three words'],
- [0, 128, 33, 'one word and one byte'],
- [0, 128, 72, 'two words and eight bytes'],
- [0, 128, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward within one word', () =>
- test([
- [0, 16, 0, 'zero bytes'],
- [0, 16, 1, 'one byte'],
- [0, 16, 11, 'eleven bytes'],
- [0, 16, 16, 'sixteen bytes'],
- ]));
-
- describe('copies backward with one byte overlap', () =>
- test([
- [0, 0, 1, 'one byte'],
- [0, 10, 11, 'eleven bytes'],
- [0, 30, 31, 'thirty-one bytes'],
- [0, 31, 32, 'one word'],
- [0, 32, 33, 'one word and one byte'],
- [0, 71, 72, 'two words and eight bytes'],
- [0, 99, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with thirty-one bytes overlap', () =>
- test([
- [0, 0, 31, 'thirty-one bytes'],
- [0, 1, 32, 'one word'],
- [0, 2, 33, 'one word and one byte'],
- [0, 41, 72, 'two words and eight bytes'],
- [0, 69, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with one word overlap', () =>
- test([
- [0, 0, 32, 'one word'],
- [0, 1, 33, 'one word and one byte'],
- [0, 41, 72, 'two words and eight bytes'],
- [0, 69, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with one word and one byte overlap', () =>
- test([
- [0, 0, 33, 'one word and one byte'],
- [0, 40, 72, 'two words and eight bytes'],
- [0, 68, 100, 'three words and four bytes'],
- ]));
-
- describe('copies backward with two words overlap', () =>
- test([
- [0, 0, 64, 'two words'],
- [0, 8, 72, 'two words and eight bytes'],
- [0, 36, 100, 'three words and four bytes'],
- ]));
-
- describe('copies forward within one word and one byte overlap', () =>
- test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']]));
- });
-});
-// tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/multisig/asset_proxy_owner.ts b/packages/contracts/test/multisig/asset_proxy_owner.ts
deleted file mode 100644
index 087152316..000000000
--- a/packages/contracts/test/multisig/asset_proxy_owner.ts
+++ /dev/null
@@ -1,498 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-
-import {
- AssetProxyOwnerAssetProxyRegistrationEventArgs,
- AssetProxyOwnerContract,
- AssetProxyOwnerExecutionEventArgs,
- AssetProxyOwnerExecutionFailureEventArgs,
- AssetProxyOwnerSubmissionEventArgs,
-} from '../../generated-wrappers/asset_proxy_owner';
-import { MixinAuthorizableContract } from '../../generated-wrappers/mixin_authorizable';
-import { TestAssetProxyOwnerContract } from '../../generated-wrappers/test_asset_proxy_owner';
-import { artifacts } from '../../src/artifacts';
-import {
- expectContractCallFailedAsync,
- expectContractCreationFailedAsync,
- expectTransactionFailedAsync,
- expectTransactionFailedWithoutReasonAsync,
- sendTransactionResult,
-} from '../utils/assertions';
-import { increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { MultiSigWrapper } from '../utils/multi_sig_wrapper';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('AssetProxyOwner', () => {
- let owners: string[];
- let authorized: string;
- let notOwner: string;
- const REQUIRED_APPROVALS = new BigNumber(2);
- const SECONDS_TIME_LOCKED = new BigNumber(1000000);
-
- let erc20Proxy: MixinAuthorizableContract;
- let erc721Proxy: MixinAuthorizableContract;
- let testAssetProxyOwner: TestAssetProxyOwnerContract;
- let multiSigWrapper: MultiSigWrapper;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owners = [accounts[0], accounts[1]];
- authorized = accounts[2];
- notOwner = accounts[3];
- const initialOwner = accounts[0];
- erc20Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- erc721Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
- artifacts.MixinAuthorizable,
- provider,
- txDefaults,
- );
- const defaultAssetProxyContractAddresses: string[] = [];
- testAssetProxyOwner = await TestAssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.TestAssetProxyOwner,
- provider,
- txDefaults,
- owners,
- defaultAssetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- multiSigWrapper = new MultiSigWrapper(testAssetProxyOwner, provider);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, {
- from: initialOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.transferOwnership.sendTransactionAsync(testAssetProxyOwner.address, {
- from: initialOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('constructor', () => {
- it('should register passed in assetProxyContracts', async () => {
- const assetProxyContractAddresses = [erc20Proxy.address, erc721Proxy.address];
- const newMultiSig = await AssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.AssetProxyOwner,
- provider,
- txDefaults,
- owners,
- assetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- const isErc20ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc20Proxy.address);
- const isErc721ProxyRegistered = await newMultiSig.isAssetProxyRegistered.callAsync(erc721Proxy.address);
- expect(isErc20ProxyRegistered).to.equal(true);
- expect(isErc721ProxyRegistered).to.equal(true);
- });
- it('should throw if a null address is included in assetProxyContracts', async () => {
- const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
- return expectContractCreationFailedAsync(
- (AssetProxyOwnerContract.deployFrom0xArtifactAsync(
- artifacts.AssetProxyOwner,
- provider,
- txDefaults,
- owners,
- assetProxyContractAddresses,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- ) as any) as sendTransactionResult,
- RevertReason.InvalidAssetProxy,
- );
- });
- });
-
- describe('isFunctionRemoveAuthorizedAddressAtIndex', () => {
- it('should return false if data is not for removeAuthorizedAddressAtIndex', async () => {
- const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- owners[0],
- );
-
- const isFunctionRemoveAuthorizedAddressAtIndex = await testAssetProxyOwner.isFunctionRemoveAuthorizedAddressAtIndex.callAsync(
- notRemoveAuthorizedAddressData,
- );
- expect(isFunctionRemoveAuthorizedAddressAtIndex).to.be.false();
- });
-
- it('should return true if data is for removeAuthorizedAddressAtIndex', async () => {
- const index = new BigNumber(0);
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- owners[0],
- index,
- );
- const isFunctionRemoveAuthorizedAddressAtIndex = await testAssetProxyOwner.isFunctionRemoveAuthorizedAddressAtIndex.callAsync(
- removeAuthorizedAddressAtIndexData,
- );
- expect(isFunctionRemoveAuthorizedAddressAtIndex).to.be.true();
- });
- });
-
- describe('registerAssetProxy', () => {
- it('should throw if not called by multisig', async () => {
- const isRegistered = true;
- return expectTransactionFailedWithoutReasonAsync(
- testAssetProxyOwner.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, {
- from: owners[0],
- }),
- );
- });
-
- it('should register an address if called by multisig after timelock', async () => {
- const addressToRegister = erc20Proxy.address;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
-
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
-
- const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
- const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerAssetProxyRegistrationEventArgs
- >;
- expect(registerLog.args.assetProxyContract).to.equal(addressToRegister);
- expect(registerLog.args.isRegistered).to.equal(isRegistered);
-
- const isAssetProxyRegistered = await testAssetProxyOwner.isAssetProxyRegistered.callAsync(
- addressToRegister,
- );
- expect(isAssetProxyRegistered).to.equal(isRegistered);
- });
-
- it('should fail if registering a null address', async () => {
- const addressToRegister = constants.NULL_ADDRESS;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
-
- const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
- const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerExecutionFailureEventArgs>;
- expect(failureLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const isAssetProxyRegistered = await testAssetProxyOwner.isAssetProxyRegistered.callAsync(
- addressToRegister,
- );
- expect(isAssetProxyRegistered).to.equal(false);
- });
- });
-
- describe('Calling removeAuthorizedAddressAtIndex', () => {
- const erc20Index = new BigNumber(0);
- const erc721Index = new BigNumber(1);
- before('authorize both proxies and register erc20 proxy', async () => {
- // Only register ERC20 proxy
- const addressToRegister = erc20Proxy.address;
- const isRegistered = true;
- const registerAssetProxyData = testAssetProxyOwner.registerAssetProxy.getABIEncodedTransactionData(
- addressToRegister,
- isRegistered,
- );
- const registerAssetProxySubmitRes = await multiSigWrapper.submitTransactionAsync(
- testAssetProxyOwner.address,
- registerAssetProxyData,
- owners[0],
- );
- const registerAssetProxySubmitLog = registerAssetProxySubmitRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerSubmissionEventArgs
- >;
-
- const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(authorized);
- const erc20AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const erc721AddAuthorizedAddressSubmitRes = await multiSigWrapper.submitTransactionAsync(
- erc721Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const erc20AddAuthorizedAddressSubmitLog = erc20AddAuthorizedAddressSubmitRes.logs[0] as LogWithDecodedArgs<
- AssetProxyOwnerSubmissionEventArgs
- >;
- const erc721AddAuthorizedAddressSubmitLog = erc721AddAuthorizedAddressSubmitRes
- .logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
-
- const registerAssetProxyTxId = registerAssetProxySubmitLog.args.transactionId;
- const erc20AddAuthorizedAddressTxId = erc20AddAuthorizedAddressSubmitLog.args.transactionId;
- const erc721AddAuthorizedAddressTxId = erc721AddAuthorizedAddressSubmitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(registerAssetProxyTxId, owners[1]);
- await multiSigWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]);
- await multiSigWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]);
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
- await multiSigWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]);
- await multiSigWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0], {
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- });
- await multiSigWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0], {
- gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
- });
- });
-
- describe('validRemoveAuthorizedAddressAtIndexTx', () => {
- it('should revert if data is not for removeAuthorizedAddressAtIndex and proxy is registered', async () => {
- const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- authorized,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- notRemoveAuthorizedAddressData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectContractCallFailedAsync(
- testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
- RevertReason.InvalidFunctionSelector,
- );
- });
-
- it('should return true if data is for removeAuthorizedAddressAtIndex and proxy is registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- const isValidRemoveAuthorizedAddressAtIndexTx = await testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(
- txId,
- );
- expect(isValidRemoveAuthorizedAddressAtIndexTx).to.be.true();
- });
-
- it('should revert if data is for removeAuthorizedAddressAtIndex and proxy is not registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc721Index,
- );
- const submitTxRes = await multiSigWrapper.submitTransactionAsync(
- erc721Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = submitTxRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectContractCallFailedAsync(
- testAssetProxyOwner.testValidRemoveAuthorizedAddressAtIndexTx.callAsync(txId),
- RevertReason.UnregisteredAssetProxy,
- );
- });
- });
-
- describe('executeRemoveAuthorizedAddressAtIndex', () => {
- it('should throw without the required confirmations', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const res = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.TxNotFullyConfirmed,
- );
- });
-
- it('should throw if tx destination is not registered', async () => {
- const removeAuthorizedAddressAtIndexData = erc721Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc721Index,
- );
- const res = await multiSigWrapper.submitTransactionAsync(
- erc721Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.UnregisteredAssetProxy,
- );
- });
-
- it('should throw if tx data is not for removeAuthorizedAddressAtIndex', async () => {
- const newAuthorized = owners[1];
- const addAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
- newAuthorized,
- );
- const res = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- addAuthorizedAddressData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = log.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- return expectTransactionFailedAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- RevertReason.InvalidFunctionSelector,
- );
- });
-
- it('should execute removeAuthorizedAddressAtIndex for registered address if fully confirmed and called by owner', async () => {
- const isAuthorizedBefore = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedBefore).to.equal(true);
-
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, owners[0]);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- const isAuthorizedAfter = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedAfter).to.equal(false);
- });
-
- it('should execute removeAuthorizedAddressAtIndex for registered address if fully confirmed and called by non-owner', async () => {
- const isAuthorizedBefore = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedBefore).to.equal(true);
-
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, notOwner);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- const isAuthorizedAfter = await erc20Proxy.authorized.callAsync(authorized);
- expect(isAuthorizedAfter).to.equal(false);
- });
-
- it('should throw if already executed', async () => {
- const removeAuthorizedAddressAtIndexData = erc20Proxy.removeAuthorizedAddressAtIndex.getABIEncodedTransactionData(
- authorized,
- erc20Index,
- );
- const submitRes = await multiSigWrapper.submitTransactionAsync(
- erc20Proxy.address,
- removeAuthorizedAddressAtIndexData,
- owners[0],
- );
- const submitLog = submitRes.logs[0] as LogWithDecodedArgs<AssetProxyOwnerSubmissionEventArgs>;
- const txId = submitLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
-
- const execRes = await multiSigWrapper.executeRemoveAuthorizedAddressAtIndexAsync(txId, owners[0]);
- const execLog = execRes.logs[1] as LogWithDecodedArgs<AssetProxyOwnerExecutionEventArgs>;
- expect(execLog.args.transactionId).to.be.bignumber.equal(txId);
-
- const tx = await testAssetProxyOwner.transactions.callAsync(txId);
- const isExecuted = tx[3];
- expect(isExecuted).to.equal(true);
-
- return expectTransactionFailedWithoutReasonAsync(
- testAssetProxyOwner.executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from: owners[1],
- }),
- );
- });
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts b/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
deleted file mode 100644
index 1c0cb0515..000000000
--- a/packages/contracts/test/multisig/multi_sig_with_time_lock.ts
+++ /dev/null
@@ -1,347 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import {
- MultiSigWalletWithTimeLockConfirmationEventArgs,
- MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs,
- MultiSigWalletWithTimeLockContract,
- MultiSigWalletWithTimeLockExecutionEventArgs,
- MultiSigWalletWithTimeLockExecutionFailureEventArgs,
- MultiSigWalletWithTimeLockSubmissionEventArgs,
-} from '../../generated-wrappers/multi_sig_wallet_with_time_lock';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { increaseTimeAndMineBlockAsync } from '../utils/block_timestamp';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { MultiSigWrapper } from '../utils/multi_sig_wrapper';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('MultiSigWalletWithTimeLock', () => {
- let owners: string[];
- let notOwner: string;
- const REQUIRED_APPROVALS = new BigNumber(2);
- const SECONDS_TIME_LOCKED = new BigNumber(1000000);
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owners = [accounts[0], accounts[1], accounts[2]];
- notOwner = accounts[3];
- });
-
- let multiSig: MultiSigWalletWithTimeLockContract;
- let multiSigWrapper: MultiSigWrapper;
-
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('external_call', () => {
- it('should be internal', async () => {
- const secondsTimeLocked = new BigNumber(0);
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- expect(_.isUndefined((multiSig as any).external_call)).to.be.equal(true);
- });
- });
- describe('confirmTransaction', () => {
- let txId: BigNumber;
- beforeEach(async () => {
- const secondsTimeLocked = new BigNumber(0);
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
- const destination = notOwner;
- const data = constants.NULL_BYTES;
- const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]);
- txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args
- .transactionId;
- });
- it('should revert if called by a non-owner', async () => {
- await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, notOwner));
- });
- it('should revert if transaction does not exist', async () => {
- const nonexistentTxId = new BigNumber(123456789);
- await expectTransactionFailedWithoutReasonAsync(
- multiSigWrapper.confirmTransactionAsync(nonexistentTxId, owners[1]),
- );
- });
- it('should revert if transaction is already confirmed by caller', async () => {
- await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, owners[0]));
- });
- it('should confirm transaction for caller and log a Confirmation event', async () => {
- const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationEventArgs>;
- expect(log.event).to.be.equal('Confirmation');
- expect(log.args.sender).to.be.equal(owners[1]);
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- it('should revert if fully confirmed', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await expectTransactionFailedAsync(
- multiSigWrapper.confirmTransactionAsync(txId, owners[2]),
- RevertReason.TxFullyConfirmed,
- );
- });
- it('should set the confirmation time of the transaction if it becomes fully confirmed', async () => {
- const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- const blockNum = await web3Wrapper.getBlockNumberAsync();
- const timestamp = new BigNumber(await web3Wrapper.getBlockTimestampAsync(blockNum));
- const log = txReceipt.logs[1] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs>;
- expect(log.args.confirmationTime).to.be.bignumber.equal(timestamp);
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- });
- describe('executeTransaction', () => {
- let txId: BigNumber;
- const secondsTimeLocked = new BigNumber(1000000);
- beforeEach(async () => {
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
- const destination = notOwner;
- const data = constants.NULL_BYTES;
- const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]);
- txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args
- .transactionId;
- });
- it('should revert if transaction has not been fully confirmed', async () => {
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- await expectTransactionFailedAsync(
- multiSigWrapper.executeTransactionAsync(txId, owners[1]),
- RevertReason.TxNotFullyConfirmed,
- );
- });
- it('should revert if time lock has not passed', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await expectTransactionFailedAsync(
- multiSigWrapper.executeTransactionAsync(txId, owners[1]),
- RevertReason.TimeLockIncomplete,
- );
- });
- it('should execute a transaction and log an Execution event if successful and called by owner', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
- expect(log.event).to.be.equal('Execution');
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- it('should execute a transaction and log an Execution event if successful and called by non-owner', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, notOwner);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
- expect(log.event).to.be.equal('Execution');
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- });
- it('should revert if a required confirmation is revoked before executeTransaction is called', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- await multiSigWrapper.revokeConfirmationAsync(txId, owners[0]);
- await expectTransactionFailedAsync(
- multiSigWrapper.executeTransactionAsync(txId, owners[1]),
- RevertReason.TxNotFullyConfirmed,
- );
- });
- it('should revert if transaction has been executed', async () => {
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
- expect(log.args.transactionId).to.be.bignumber.equal(txId);
- await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.executeTransactionAsync(txId, owners[1]));
- });
- it("should log an ExecutionFailure event and not update the transaction's execution state if unsuccessful", async () => {
- const contractWithoutFallback = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- const data = constants.NULL_BYTES;
- const value = new BigNumber(10);
- const submissionTxReceipt = await multiSigWrapper.submitTransactionAsync(
- contractWithoutFallback.address,
- data,
- owners[0],
- { value },
- );
- const newTxId = (submissionTxReceipt.logs[0] as LogWithDecodedArgs<
- MultiSigWalletWithTimeLockSubmissionEventArgs
- >).args.transactionId;
- await multiSigWrapper.confirmTransactionAsync(newTxId, owners[1]);
- await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
- const txReceipt = await multiSigWrapper.executeTransactionAsync(newTxId, owners[1]);
- const executionFailureLog = txReceipt.logs[0] as LogWithDecodedArgs<
- MultiSigWalletWithTimeLockExecutionFailureEventArgs
- >;
- expect(executionFailureLog.event).to.be.equal('ExecutionFailure');
- expect(executionFailureLog.args.transactionId).to.be.bignumber.equal(newTxId);
- });
- });
- describe('changeTimeLock', () => {
- describe('initially non-time-locked', async () => {
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before('deploy a wallet', async () => {
- const secondsTimeLocked = new BigNumber(0);
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- secondsTimeLocked,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
- });
-
- it('should throw when not called by wallet', async () => {
- return expectTransactionFailedWithoutReasonAsync(
- multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
- );
- });
-
- it('should throw without enough confirmations', async () => {
- const destination = multiSig.address;
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
- const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
- const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- const txId = log.args.transactionId;
- return expectTransactionFailedAsync(
- multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
- RevertReason.TxNotFullyConfirmed,
- );
- });
-
- it('should set confirmation time with enough confirmations', async () => {
- const destination = multiSig.address;
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
- const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
- const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- const txId = subLog.args.transactionId;
-
- const confirmRes = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- expect(confirmRes.logs).to.have.length(2);
-
- const blockNum = await web3Wrapper.getBlockNumberAsync();
- const blockInfo = await web3Wrapper.getBlockIfExistsAsync(blockNum);
- if (_.isUndefined(blockInfo)) {
- throw new Error(`Unexpectedly failed to fetch block at #${blockNum}`);
- }
- const timestamp = new BigNumber(blockInfo.timestamp);
- const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId));
-
- expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum);
- });
-
- it('should be executable with enough confirmations and secondsTimeLocked of 0', async () => {
- const destination = multiSig.address;
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
- const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
- const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- const txId = subLog.args.transactionId;
-
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
-
- const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
- expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED);
- });
- });
- describe('initially time-locked', async () => {
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- let txId: BigNumber;
- const newSecondsTimeLocked = new BigNumber(0);
- before('deploy a wallet, submit transaction to change timelock, and confirm the transaction', async () => {
- multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
- artifacts.MultiSigWalletWithTimeLock,
- provider,
- txDefaults,
- owners,
- REQUIRED_APPROVALS,
- SECONDS_TIME_LOCKED,
- );
- multiSigWrapper = new MultiSigWrapper(multiSig, provider);
-
- const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(newSecondsTimeLocked);
- const res = await multiSigWrapper.submitTransactionAsync(
- multiSig.address,
- changeTimeLockData,
- owners[0],
- );
- const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
- txId = log.args.transactionId;
- await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
- });
-
- it('should throw if it has enough confirmations but is not past the time lock', async () => {
- return expectTransactionFailedAsync(
- multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
- RevertReason.TimeLockIncomplete,
- );
- });
-
- it('should execute if it has enough confirmations and is past the time lock', async () => {
- await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
- await web3Wrapper.awaitTransactionSuccessAsync(
- await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
- expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked);
- });
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/tokens/erc721_token.ts b/packages/contracts/test/tokens/erc721_token.ts
deleted file mode 100644
index 72407748f..000000000
--- a/packages/contracts/test/tokens/erc721_token.ts
+++ /dev/null
@@ -1,279 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import { LogWithDecodedArgs } from 'ethereum-types';
-
-import {
- DummyERC721ReceiverContract,
- DummyERC721ReceiverTokenReceivedEventArgs,
-} from '../../generated-wrappers/dummy_erc721_receiver';
-import {
- DummyERC721TokenContract,
- DummyERC721TokenTransferEventArgs,
-} from '../../generated-wrappers/dummy_erc721_token';
-import { InvalidERC721ReceiverContract } from '../../generated-wrappers/invalid_erc721_receiver';
-import { artifacts } from '../../src/artifacts';
-import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { LogDecoder } from '../utils/log_decoder';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-// tslint:disable:no-unnecessary-type-assertion
-describe('ERC721Token', () => {
- let owner: string;
- let spender: string;
- let token: DummyERC721TokenContract;
- let erc721Receiver: DummyERC721ReceiverContract;
- let logDecoder: LogDecoder;
- const tokenId = new BigNumber(1);
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owner = accounts[0];
- spender = accounts[1];
- token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- );
- erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Receiver,
- provider,
- txDefaults,
- );
- logDecoder = new LogDecoder(web3Wrapper);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.mint.sendTransactionAsync(owner, tokenId, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
-
- describe('transferFrom', () => {
- it('should revert if the tokenId is not owner', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const unownedTokenId = new BigNumber(2);
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, unownedTokenId),
- RevertReason.Erc721ZeroOwner,
- );
- });
- it('should revert if transferring to a null address', async () => {
- const from = owner;
- const to = constants.NULL_ADDRESS;
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, tokenId),
- RevertReason.Erc721ZeroToAddress,
- );
- });
- it('should revert if the from address does not own the token', async () => {
- const from = spender;
- const to = erc721Receiver.address;
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, tokenId),
- RevertReason.Erc721OwnerMismatch,
- );
- });
- it('should revert if spender does not own the token, is not approved, and is not approved for all', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- await expectTransactionFailedAsync(
- token.transferFrom.sendTransactionAsync(from, to, tokenId, { from: spender }),
- RevertReason.Erc721InvalidSpender,
- );
- });
- it('should transfer the token if called by owner', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.transferFrom.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should transfer the token if spender is approved for all', async () => {
- const isApproved = true;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.setApprovalForAll.sendTransactionAsync(spender, isApproved),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.transferFrom.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should transfer the token if spender is individually approved', async () => {
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, tokenId),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.transferFrom.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
-
- const approvedAddress = await token.getApproved.callAsync(tokenId);
- expect(approvedAddress).to.be.equal(constants.NULL_ADDRESS);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- });
- describe('safeTransferFrom without data', () => {
- it('should transfer token to a non-contract address if called by owner', async () => {
- const from = owner;
- const to = spender;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should revert if transferring to a contract address without onERC721Received', async () => {
- const contract = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- );
- const from = owner;
- const to = contract.address;
- await expectTransactionFailedWithoutReasonAsync(
- token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- );
- });
- it('should revert if onERC721Received does not return the correct value', async () => {
- const invalidErc721Receiver = await InvalidERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.InvalidERC721Receiver,
- provider,
- txDefaults,
- );
- const from = owner;
- const to = invalidErc721Receiver.address;
- await expectTransactionFailedAsync(
- token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- RevertReason.Erc721InvalidSelector,
- );
- });
- it('should transfer to contract and call onERC721Received with correct return value', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom1.sendTransactionAsync(from, to, tokenId),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const transferLog = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<DummyERC721ReceiverTokenReceivedEventArgs>;
- expect(transferLog.args._from).to.be.equal(from);
- expect(transferLog.args._to).to.be.equal(to);
- expect(transferLog.args._tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.operator).to.be.equal(owner);
- expect(receiverLog.args.from).to.be.equal(from);
- expect(receiverLog.args.tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.data).to.be.equal(constants.NULL_BYTES);
- });
- });
- describe('safeTransferFrom with data', () => {
- const data = '0x0102030405060708090a0b0c0d0e0f';
- it('should transfer token to a non-contract address if called by owner', async () => {
- const from = owner;
- const to = spender;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const log = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- expect(log.args._from).to.be.equal(from);
- expect(log.args._to).to.be.equal(to);
- expect(log.args._tokenId).to.be.bignumber.equal(tokenId);
- });
- it('should revert if transferring to a contract address without onERC721Received', async () => {
- const contract = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- );
- const from = owner;
- const to = contract.address;
- await expectTransactionFailedWithoutReasonAsync(
- token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- );
- });
- it('should revert if onERC721Received does not return the correct value', async () => {
- const invalidErc721Receiver = await InvalidERC721ReceiverContract.deployFrom0xArtifactAsync(
- artifacts.InvalidERC721Receiver,
- provider,
- txDefaults,
- );
- const from = owner;
- const to = invalidErc721Receiver.address;
- await expectTransactionFailedAsync(
- token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- RevertReason.Erc721InvalidSelector,
- );
- });
- it('should transfer to contract and call onERC721Received with correct return value', async () => {
- const from = owner;
- const to = erc721Receiver.address;
- const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
- await token.safeTransferFrom2.sendTransactionAsync(from, to, tokenId, data),
- );
- const newOwner = await token.ownerOf.callAsync(tokenId);
- expect(newOwner).to.be.equal(to);
- const transferLog = txReceipt.logs[0] as LogWithDecodedArgs<DummyERC721TokenTransferEventArgs>;
- const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<DummyERC721ReceiverTokenReceivedEventArgs>;
- expect(transferLog.args._from).to.be.equal(from);
- expect(transferLog.args._to).to.be.equal(to);
- expect(transferLog.args._tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.operator).to.be.equal(owner);
- expect(receiverLog.args.from).to.be.equal(from);
- expect(receiverLog.args.tokenId).to.be.bignumber.equal(tokenId);
- expect(receiverLog.args.data).to.be.equal(data);
- });
- });
-});
-// tslint:enable:no-unnecessary-type-assertion
diff --git a/packages/contracts/test/tokens/unlimited_allowance_token.ts b/packages/contracts/test/tokens/unlimited_allowance_token.ts
deleted file mode 100644
index ea5a50522..000000000
--- a/packages/contracts/test/tokens/unlimited_allowance_token.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { RevertReason } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { artifacts } from '../../src/artifacts';
-import { expectContractCallFailedAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('UnlimitedAllowanceToken', () => {
- let owner: string;
- let spender: string;
- const MAX_MINT_VALUE = new BigNumber(10000000000000000000000);
- let token: DummyERC20TokenContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owner = accounts[0];
- spender = accounts[1];
- token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC20Token,
- provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- constants.DUMMY_TOKEN_DECIMALS,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.mint.sendTransactionAsync(MAX_MINT_VALUE, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('transfer', () => {
- it('should throw if owner has insufficient balance', async () => {
- const ownerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance.plus(1);
- return expectContractCallFailedAsync(
- token.transfer.callAsync(spender, amountToTransfer, { from: owner }),
- RevertReason.Erc20InsufficientBalance,
- );
- });
-
- it('should transfer balance from sender to receiver', async () => {
- const receiver = spender;
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = new BigNumber(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const finalOwnerBalance = await token.balanceOf.callAsync(owner);
- const finalReceiverBalance = await token.balanceOf.callAsync(receiver);
-
- const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
- const expectedFinalReceiverBalance = amountToTransfer;
- expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
- expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
- });
-
- it('should return true on a 0 value transfer', async () => {
- const didReturnTrue = await token.transfer.callAsync(spender, new BigNumber(0), {
- from: owner,
- });
- expect(didReturnTrue).to.be.true();
- });
- });
-
- describe('transferFrom', () => {
- it('should throw if owner has insufficient balance', async () => {
- const ownerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance.plus(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, amountToTransfer, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- return expectContractCallFailedAsync(
- token.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- }),
- RevertReason.Erc20InsufficientBalance,
- );
- });
-
- it('should throw if spender has insufficient allowance', async () => {
- const ownerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance;
-
- const spenderAllowance = await token.allowance.callAsync(owner, spender);
- const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
- expect(isSpenderAllowanceInsufficient).to.be.true();
-
- return expectContractCallFailedAsync(
- token.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- }),
- RevertReason.Erc20InsufficientAllowance,
- );
- });
-
- it('should return true on a 0 value transfer', async () => {
- const amountToTransfer = new BigNumber(0);
- const didReturnTrue = await token.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.true();
- });
-
- it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, initSpenderAllowance, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await token.allowance.callAsync(owner, spender);
- expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
- });
-
- it('should transfer the correct balances if spender has sufficient allowance', async () => {
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, initSpenderAllowance, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newOwnerBalance = await token.balanceOf.callAsync(owner);
- const newSpenderBalance = await token.balanceOf.callAsync(spender);
-
- expect(newOwnerBalance).to.be.bignumber.equal(0);
- expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance);
- });
-
- it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
- const initOwnerBalance = await token.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.approve.sendTransactionAsync(spender, initSpenderAllowance, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await token.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await token.allowance.callAsync(owner, spender);
- expect(newSpenderAllowance).to.be.bignumber.equal(0);
- });
- });
-});
diff --git a/packages/contracts/test/tokens/weth9.ts b/packages/contracts/test/tokens/weth9.ts
deleted file mode 100644
index 9a31dc3f2..000000000
--- a/packages/contracts/test/tokens/weth9.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-
-import { WETH9Contract } from '../../generated-wrappers/weth9';
-import { artifacts } from '../../src/artifacts';
-import { expectInsufficientFundsAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('EtherToken', () => {
- let account: string;
- const gasPrice = Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 9);
- let etherToken: WETH9Contract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- account = accounts[0];
-
- etherToken = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, {
- gasPrice,
- ...txDefaults,
- });
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('deposit', () => {
- it('should throw if caller attempts to deposit more Ether than caller balance', async () => {
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const ethToDeposit = initEthBalance.plus(1);
-
- return expectInsufficientFundsAsync(etherToken.deposit.sendTransactionAsync({ value: ethToDeposit }));
- });
-
- it('should convert deposited Ether to wrapped Ether tokens', async () => {
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
-
- const txHash = await etherToken.deposit.sendTransactionAsync({ value: ethToDeposit });
- const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
- txHash,
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
- const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const finalEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
- expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
- });
- });
-
- describe('withdraw', () => {
- it('should throw if caller attempts to withdraw greater than caller balance', async () => {
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
- const ethTokensToWithdraw = initEthTokenBalance.plus(1);
-
- return expectTransactionFailedWithoutReasonAsync(
- etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw),
- );
- });
-
- it('should convert ether tokens to ether with sufficient balance', async () => {
- const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
- await web3Wrapper.awaitTransactionSuccessAsync(
- await etherToken.deposit.sendTransactionAsync({ value: ethToDeposit }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const ethTokensToWithdraw = initEthTokenBalance;
- expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0);
- const txHash = await etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw, {
- gas: constants.MAX_ETHERTOKEN_WITHDRAW_GAS,
- });
- const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
- txHash,
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
- const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const finalEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- expect(finalEthBalance).to.be.bignumber.equal(
- initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)),
- );
- expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw));
- });
- });
-
- describe('fallback', () => {
- it('should convert sent ether to ether tokens', async () => {
- const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- const ethToDeposit = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18);
-
- const txHash = await web3Wrapper.sendTransactionAsync({
- from: account,
- to: etherToken.address,
- value: ethToDeposit,
- gasPrice,
- });
-
- const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
- txHash,
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
- const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
- const finalEthTokenBalance = await etherToken.balanceOf.callAsync(account);
-
- expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
- expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
- });
- });
-});
diff --git a/packages/contracts/test/tokens/zrx_token.ts b/packages/contracts/test/tokens/zrx_token.ts
deleted file mode 100644
index cab62c205..000000000
--- a/packages/contracts/test/tokens/zrx_token.ts
+++ /dev/null
@@ -1,206 +0,0 @@
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-
-import { ZRXTokenContract } from '../../generated-wrappers/zrx_token';
-import { artifacts } from '../../src/artifacts';
-import { chaiSetup } from '../utils/chai_setup';
-import { constants } from '../utils/constants';
-import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('ZRXToken', () => {
- let owner: string;
- let spender: string;
- let MAX_UINT: BigNumber;
- let zrxToken: ZRXTokenContract;
-
- before(async () => {
- await blockchainLifecycle.startAsync();
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- before(async () => {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- owner = accounts[0];
- spender = accounts[1];
- zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync(artifacts.ZRXToken, provider, txDefaults);
- MAX_UINT = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('constants', () => {
- it('should have 18 decimals', async () => {
- const decimals = new BigNumber(await zrxToken.decimals.callAsync());
- const expectedDecimals = 18;
- expect(decimals).to.be.bignumber.equal(expectedDecimals);
- });
-
- it('should have a total supply of 1 billion tokens', async () => {
- const totalSupply = new BigNumber(await zrxToken.totalSupply.callAsync());
- const expectedTotalSupply = 1000000000;
- expect(Web3Wrapper.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply);
- });
-
- it('should be named 0x Protocol Token', async () => {
- const name = await zrxToken.name.callAsync();
- const expectedName = '0x Protocol Token';
- expect(name).to.be.equal(expectedName);
- });
-
- it('should have the symbol ZRX', async () => {
- const symbol = await zrxToken.symbol.callAsync();
- const expectedSymbol = 'ZRX';
- expect(symbol).to.be.equal(expectedSymbol);
- });
- });
-
- describe('constructor', () => {
- it('should initialize owner balance to totalSupply', async () => {
- const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
- const totalSupply = new BigNumber(await zrxToken.totalSupply.callAsync());
- expect(totalSupply).to.be.bignumber.equal(ownerBalance);
- });
- });
-
- describe('transfer', () => {
- it('should transfer balance from sender to receiver', async () => {
- const receiver = spender;
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = new BigNumber(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const finalOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const finalReceiverBalance = await zrxToken.balanceOf.callAsync(receiver);
-
- const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
- const expectedFinalReceiverBalance = amountToTransfer;
- expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
- expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
- });
-
- it('should return true on a 0 value transfer', async () => {
- const didReturnTrue = await zrxToken.transfer.callAsync(spender, new BigNumber(0), {
- from: owner,
- });
- expect(didReturnTrue).to.be.true();
- });
- });
-
- describe('transferFrom', () => {
- it('should return false if owner has insufficient balance', async () => {
- const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance.plus(1);
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer, {
- from: owner,
- gas: constants.MAX_TOKEN_APPROVE_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.false();
- });
-
- it('should return false if spender has insufficient allowance', async () => {
- const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = ownerBalance;
-
- const spenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
- const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
- expect(isSpenderAllowanceInsufficient).to.be.true();
-
- const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.false();
- });
-
- it('should return true on a 0 value transfer', async () => {
- const amountToTransfer = new BigNumber(0);
- const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
- from: spender,
- });
- expect(didReturnTrue).to.be.true();
- });
-
- it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = MAX_UINT;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance, {
- from: owner,
- gas: constants.MAX_TOKEN_APPROVE_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
- expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
- });
-
- it('should transfer the correct balances if spender has sufficient allowance', async () => {
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const initSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
- const amountToTransfer = initOwnerBalance;
- const initSpenderAllowance = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const newSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
-
- expect(newOwnerBalance).to.be.bignumber.equal(0);
- expect(newSpenderBalance).to.be.bignumber.equal(initSpenderBalance.plus(initOwnerBalance));
- });
-
- it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
- const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
- const amountToTransfer = initOwnerBalance;
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
- from: spender,
- gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
- expect(newSpenderAllowance).to.be.bignumber.equal(0);
- });
- });
-});
diff --git a/packages/contracts/test/tutorials/arbitrage.ts b/packages/contracts/test/tutorials/arbitrage.ts
deleted file mode 100644
index 78e0bc238..000000000
--- a/packages/contracts/test/tutorials/arbitrage.ts
+++ /dev/null
@@ -1,260 +0,0 @@
-// import { ECSignature, SignedOrder, ZeroEx } from '0x.js';
-// import { BlockchainLifecycle, devConstants, web3Factory } from '@0x/dev-utils';
-// import { ExchangeContractErrs } from 'ethereum-types';
-// import { BigNumber } from '@0x/utils';
-// import { Web3Wrapper } from '@0x/web3-wrapper';
-// import * as chai from 'chai';
-// import ethUtil = require('ethereumjs-util');
-// import * as Web3 from 'web3';
-
-// import { AccountLevelsContract } from '../../src/generated_contract_wrappers/account_levels';
-// import { ArbitrageContract } from '../../src/generated_contract_wrappers/arbitrage';
-// import { DummyTokenContract } from '../../src/generated_contract_wrappers/dummy_token';
-// import { EtherDeltaContract } from '../../src/generated_contract_wrappers/ether_delta';
-// import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
-// import { TokenTransferProxyContract } from '../../src/generated_contract_wrappers/token_transfer_proxy';
-// import { artifacts } from '../../util/artifacts';
-// import { Balances } from '../../util/balances';
-// import { constants } from '../../util/constants';
-// import { crypto } from '../../util/crypto';
-// import { ExchangeWrapper } from '../../util/exchange_wrapper';
-// import { OrderFactory } from '../../util/order_factory';
-// import { BalancesByOwner, ContractName } from '../../util/types';
-// import { chaiSetup } from '../utils/chai_setup';
-
-// import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
-
-// chaiSetup.configure();
-// const expect = chai.expect;
-// const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-// describe('Arbitrage', () => {
-// let coinbase: string;
-// let maker: string;
-// let edMaker: string;
-// let edFrontRunner: string;
-// let amountGet: BigNumber;
-// let amountGive: BigNumber;
-// let makerTokenAmount: BigNumber;
-// let takerTokenAmount: BigNumber;
-// const feeRecipient = constants.NULL_ADDRESS;
-// const INITIAL_BALANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
-// const INITIAL_ALLOWANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
-
-// let weth: DummyTokenContract;
-// let zrx: DummyTokenContract;
-// let arbitrage: ArbitrageContract;
-// let etherDelta: EtherDeltaContract;
-
-// let signedOrder: SignedOrder;
-// let exWrapper: ExchangeWrapper;
-// let orderFactory: OrderFactory;
-
-// let zeroEx: ZeroEx;
-
-// // From a bird's eye view - we create two orders.
-// // 0x order of 1 ZRX (maker) for 1 WETH (taker)
-// // ED order of 2 WETH (tokenGive) for 1 ZRX (tokenGet)
-// // And then we do an atomic arbitrage between them which gives us 1 WETH.
-// before(async () => {
-// const accounts = await web3Wrapper.getAvailableAddressesAsync();
-// [coinbase, maker, edMaker, edFrontRunner] = accounts;
-// weth = await DummyTokenContract.deployFrom0xArtifactAsync(
-// artifacts.DummyToken,
-// provider,
-// txDefaults,
-// constants.DUMMY_TOKEN_NAME,
-// constants.DUMMY_TOKEN_SYMBOL,
-// constants.DUMMY_TOKEN_DECIMALS,
-// constants.DUMMY_TOKEN_TOTAL_SUPPLY,
-// );
-// zrx = await DummyTokenContract.deployFrom0xArtifactAsync(
-// artifacts.DummyToken,
-// provider,
-// txDefaults,
-// constants.DUMMY_TOKEN_NAME,
-// constants.DUMMY_TOKEN_SYMBOL,
-// constants.DUMMY_TOKEN_DECIMALS,
-// constants.DUMMY_TOKEN_TOTAL_SUPPLY,
-// );
-// const accountLevels = await AccountLevelsContract.deployFrom0xArtifactAsync(
-// artifacts.AccountLevels,
-// provider,
-// txDefaults,
-// );
-// const edAdminAddress = accounts[0];
-// const edMakerFee = new BigNumber(0);
-// const edTakerFee = new BigNumber(0);
-// const edFeeRebate = new BigNumber(0);
-// etherDelta = await EtherDeltaContract.deployFrom0xArtifactAsync(
-// artifacts.EtherDelta,
-// provider,
-// txDefaults,
-// edAdminAddress,
-// feeRecipient,
-// accountLevels.address,
-// edMakerFee,
-// edTakerFee,
-// edFeeRebate,
-// );
-// const tokenTransferProxy = await TokenTransferProxyContract.deployFrom0xArtifactAsync(
-// artifacts.TokenTransferProxy,
-// provider,
-// txDefaults,
-// );
-// const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
-// artifacts.Exchange,
-// provider,
-// txDefaults,
-// zrx.address,
-// tokenTransferProxy.address,
-// );
-// await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] });
-// zeroEx = new ZeroEx(provider, {
-// exchangeContractAddress: exchange.address,
-// networkId: constants.TESTRPC_NETWORK_ID,
-// });
-// exWrapper = new ExchangeWrapper(exchange, provider);
-
-// makerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18);
-// takerTokenAmount = makerTokenAmount;
-// const defaultOrderParams = {
-// exchangeContractAddress: exchange.address,
-// maker,
-// feeRecipient,
-// makerTokenAddress: zrx.address,
-// takerTokenAddress: weth.address,
-// makerTokenAmount,
-// takerTokenAmount,
-// makerFee: new BigNumber(0),
-// takerFee: new BigNumber(0),
-// };
-// orderFactory = new OrderFactory(zeroEx, defaultOrderParams);
-// arbitrage = await ArbitrageContract.deployFrom0xArtifactAsync(
-// artifacts.Arbitrage,
-// provider,
-// txDefaults,
-// exchange.address,
-// etherDelta.address,
-// tokenTransferProxy.address,
-// );
-// // Enable arbitrage and withdrawals of tokens
-// await arbitrage.setAllowances.sendTransactionAsync(weth.address, { from: coinbase });
-// await arbitrage.setAllowances.sendTransactionAsync(zrx.address, { from: coinbase });
-
-// // Give some tokens to arbitrage contract
-// await weth.setBalance.sendTransactionAsync(arbitrage.address, takerTokenAmount, { from: coinbase });
-
-// // Fund the maker on exchange side
-// await zrx.setBalance.sendTransactionAsync(maker, makerTokenAmount, { from: coinbase });
-// // Set the allowance for the maker on Exchange side
-// await zrx.approve.sendTransactionAsync(tokenTransferProxy.address, INITIAL_ALLOWANCE, { from: maker });
-
-// amountGive = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
-// // Fund the maker on EtherDelta side
-// await weth.setBalance.sendTransactionAsync(edMaker, amountGive, { from: coinbase });
-// // Set the allowance for the maker on EtherDelta side
-// await weth.approve.sendTransactionAsync(etherDelta.address, INITIAL_ALLOWANCE, { from: edMaker });
-// // Deposit maker funds into EtherDelta
-// await etherDelta.depositToken.sendTransactionAsync(weth.address, amountGive, { from: edMaker });
-
-// amountGet = makerTokenAmount;
-// // Fund the front runner on EtherDelta side
-// await zrx.setBalance.sendTransactionAsync(edFrontRunner, amountGet, { from: coinbase });
-// // Set the allowance for the front-runner on EtherDelta side
-// await zrx.approve.sendTransactionAsync(etherDelta.address, INITIAL_ALLOWANCE, { from: edFrontRunner });
-// // Deposit front runner funds into EtherDelta
-// await etherDelta.depositToken.sendTransactionAsync(zrx.address, amountGet, { from: edFrontRunner });
-// });
-// beforeEach(async () => {
-// await blockchainLifecycle.startAsync();
-// });
-// afterEach(async () => {
-// await blockchainLifecycle.revertAsync();
-// });
-// describe('makeAtomicTrade', () => {
-// let addresses: string[];
-// let values: BigNumber[];
-// let v: number[];
-// let r: string[];
-// let s: string[];
-// let tokenGet: string;
-// let tokenGive: string;
-// let expires: BigNumber;
-// let nonce: BigNumber;
-// let edSignature: ECSignature;
-// before(async () => {
-// signedOrder = await orderFactory.newSignedOrderAsync();
-// tokenGet = zrx.address;
-// tokenGive = weth.address;
-// const blockNumber = await web3Wrapper.getBlockNumberAsync();
-// const ED_ORDER_EXPIRATION_IN_BLOCKS = 10;
-// expires = new BigNumber(blockNumber + ED_ORDER_EXPIRATION_IN_BLOCKS);
-// nonce = new BigNumber(42);
-// const edOrderHash = `0x${crypto
-// .solSHA256([etherDelta.address, tokenGet, amountGet, tokenGive, amountGive, expires, nonce])
-// .toString('hex')}`;
-// const shouldAddPersonalMessagePrefix = false;
-// edSignature = await zeroEx.signOrderHashAsync(edOrderHash, edMaker, shouldAddPersonalMessagePrefix);
-// addresses = [
-// signedOrder.maker,
-// signedOrder.taker,
-// signedOrder.makerTokenAddress,
-// signedOrder.takerTokenAddress,
-// signedOrder.feeRecipient,
-// edMaker,
-// ];
-// const fillTakerTokenAmount = takerTokenAmount;
-// const edFillAmount = makerTokenAmount;
-// values = [
-// signedOrder.makerTokenAmount,
-// signedOrder.takerTokenAmount,
-// signedOrder.makerFee,
-// signedOrder.takerFee,
-// signedOrder.expirationUnixTimestampSec,
-// signedOrder.salt,
-// fillTakerTokenAmount,
-// amountGet,
-// amountGive,
-// expires,
-// nonce,
-// edFillAmount,
-// ];
-// v = [signedOrder.ecSignature.v, edSignature.v];
-// r = [signedOrder.ecSignature.r, edSignature.r];
-// s = [signedOrder.ecSignature.s, edSignature.s];
-// });
-// it('should successfully execute the arbitrage if not front-runned', async () => {
-// const txHash = await arbitrage.makeAtomicTrade.sendTransactionAsync(addresses, values, v, r, s, {
-// from: coinbase,
-// });
-// const res = await zeroEx.awaitTransactionMinedAsync(txHash);
-// const postBalance = await weth.balanceOf.callAsync(arbitrage.address);
-// expect(postBalance).to.be.bignumber.equal(amountGive);
-// });
-// it('should fail and revert if front-runned', async () => {
-// const preBalance = await weth.balanceOf.callAsync(arbitrage.address);
-// // Front-running transaction
-// await etherDelta.trade.sendTransactionAsync(
-// tokenGet,
-// amountGet,
-// tokenGive,
-// amountGive,
-// expires,
-// nonce,
-// edMaker,
-// edSignature.v,
-// edSignature.r,
-// edSignature.s,
-// amountGet,
-// { from: edFrontRunner },
-// );
-// // tslint:disable-next-line:await-promise
-// await expect(
-// arbitrage.makeAtomicTrade.sendTransactionAsync(addresses, values, v, r, s, { from: coinbase }),
-// ).to.be.rejectedWith(constants.REVERT);
-// const postBalance = await weth.balanceOf.callAsync(arbitrage.address);
-// expect(preBalance).to.be.bignumber.equal(postBalance);
-// });
-// });
-// });
diff --git a/packages/contracts/test/utils/abstract_asset_wrapper.ts b/packages/contracts/test/utils/abstract_asset_wrapper.ts
deleted file mode 100644
index 4b56a8502..000000000
--- a/packages/contracts/test/utils/abstract_asset_wrapper.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export abstract class AbstractAssetWrapper {
- public abstract getProxyId(): string;
-}
diff --git a/packages/contracts/test/utils/address_utils.ts b/packages/contracts/test/utils/address_utils.ts
deleted file mode 100644
index 634da0c16..000000000
--- a/packages/contracts/test/utils/address_utils.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { crypto } from '@0x/order-utils/lib/src/crypto';
-
-export const addressUtils = {
- generatePseudoRandomAddress(): string {
- const randomBigNum = generatePseudoRandomSalt();
- const randomBuff = crypto.solSHA3([randomBigNum]);
- const randomAddress = `0x${randomBuff.slice(0, 20).toString('hex')}`;
- return randomAddress;
- },
-};
diff --git a/packages/contracts/test/utils/assertions.ts b/packages/contracts/test/utils/assertions.ts
deleted file mode 100644
index 5b1cedfcc..000000000
--- a/packages/contracts/test/utils/assertions.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { RevertReason } from '@0x/types';
-import { logUtils } from '@0x/utils';
-import { NodeType } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { TransactionReceipt, TransactionReceiptStatus, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { web3Wrapper } from './web3_wrapper';
-
-const expect = chai.expect;
-
-let nodeType: NodeType | undefined;
-
-// Represents the return value of a `sendTransaction` call. The Promise should
-// resolve with either a transaction receipt or a transaction hash.
-export type sendTransactionResult = Promise<TransactionReceipt | TransactionReceiptWithDecodedLogs | string>;
-
-/**
- * Returns ganacheError if the backing Ethereum node is Ganache and gethError
- * if it is Geth.
- * @param ganacheError the error to be returned if the backing node is Ganache.
- * @param gethError the error to be returned if the backing node is Geth.
- * @returns either the given ganacheError or gethError depending on the backing
- * node.
- */
-async function _getGanacheOrGethError(ganacheError: string, gethError: string): Promise<string> {
- if (_.isUndefined(nodeType)) {
- nodeType = await web3Wrapper.getNodeTypeAsync();
- }
- switch (nodeType) {
- case NodeType.Ganache:
- return ganacheError;
- case NodeType.Geth:
- return gethError;
- default:
- throw new Error(`Unknown node type: ${nodeType}`);
- }
-}
-
-async function _getInsufficientFundsErrorMessageAsync(): Promise<string> {
- return _getGanacheOrGethError("sender doesn't have enough funds", 'insufficient funds');
-}
-
-async function _getTransactionFailedErrorMessageAsync(): Promise<string> {
- return _getGanacheOrGethError('revert', 'always failing transaction');
-}
-
-async function _getContractCallFailedErrorMessageAsync(): Promise<string> {
- return _getGanacheOrGethError('revert', 'Contract call failed');
-}
-
-/**
- * Returns the expected error message for an 'invalid opcode' resulting from a
- * contract call. The exact error message depends on the backing Ethereum node.
- */
-export async function getInvalidOpcodeErrorMessageForCallAsync(): Promise<string> {
- return _getGanacheOrGethError('invalid opcode', 'Contract call failed');
-}
-
-/**
- * Returns the expected error message for the given revert reason resulting from
- * a sendTransaction call. The exact error message depends on the backing
- * Ethereum node and whether it supports revert reasons.
- * @param reason a specific revert reason.
- * @returns the expected error message.
- */
-export async function getRevertReasonOrErrorMessageForSendTransactionAsync(reason: RevertReason): Promise<string> {
- return _getGanacheOrGethError(reason, 'always failing transaction');
-}
-
-/**
- * Rejects if the given Promise does not reject with an error indicating
- * insufficient funds.
- * @param p a promise resulting from a contract call or sendTransaction call.
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectInsufficientFundsAsync<T>(p: Promise<T>): Promise<void> {
- const errMessage = await _getInsufficientFundsErrorMessageAsync();
- return expect(p).to.be.rejectedWith(errMessage);
-}
-
-/**
- * Resolves if the the sendTransaction call fails with the given revert reason.
- * However, since Geth does not support revert reasons for sendTransaction, this
- * falls back to expectTransactionFailedWithoutReasonAsync if the backing
- * Ethereum node is Geth.
- * @param p a Promise resulting from a sendTransaction call
- * @param reason a specific revert reason
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectTransactionFailedAsync(p: sendTransactionResult, reason: RevertReason): Promise<void> {
- // HACK(albrow): This dummy `catch` should not be necessary, but if you
- // remove it, there is an uncaught exception and the Node process will
- // forcibly exit. It's possible this is a false positive in
- // make-promises-safe.
- p.catch(e => {
- _.noop(e);
- });
-
- if (_.isUndefined(nodeType)) {
- nodeType = await web3Wrapper.getNodeTypeAsync();
- }
- switch (nodeType) {
- case NodeType.Ganache:
- return expect(p).to.be.rejectedWith(reason);
- case NodeType.Geth:
- logUtils.warn(
- 'WARNING: Geth does not support revert reasons for sendTransaction. This test will pass if the transaction fails for any reason.',
- );
- return expectTransactionFailedWithoutReasonAsync(p);
- default:
- throw new Error(`Unknown node type: ${nodeType}`);
- }
-}
-
-/**
- * Resolves if the transaction fails without a revert reason, or if the
- * corresponding transactionReceipt has a status of 0 or '0', indicating
- * failure.
- * @param p a Promise resulting from a sendTransaction call
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectTransactionFailedWithoutReasonAsync(p: sendTransactionResult): Promise<void> {
- return p
- .then(async result => {
- let txReceiptStatus: TransactionReceiptStatus;
- if (_.isString(result)) {
- // Result is a txHash. We need to make a web3 call to get the
- // receipt, then get the status from the receipt.
- const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(result);
- txReceiptStatus = txReceipt.status;
- } else if ('status' in result) {
- // Result is a transaction receipt, so we can get the status
- // directly.
- txReceiptStatus = result.status;
- } else {
- throw new Error('Unexpected result type: ' + typeof result);
- }
- expect(_.toString(txReceiptStatus)).to.equal(
- '0',
- 'Expected transaction to fail but receipt had a non-zero status, indicating success',
- );
- })
- .catch(async err => {
- // If the promise rejects, we expect a specific error message,
- // depending on the backing Ethereum node type.
- const errMessage = await _getTransactionFailedErrorMessageAsync();
- expect(err.message).to.include(errMessage);
- });
-}
-
-/**
- * Resolves if the the contract call fails with the given revert reason.
- * @param p a Promise resulting from a contract call
- * @param reason a specific revert reason
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCallFailedAsync<T>(p: Promise<T>, reason: RevertReason): Promise<void> {
- return expect(p).to.be.rejectedWith(reason);
-}
-
-/**
- * Resolves if the contract call fails without a revert reason.
- * @param p a Promise resulting from a contract call
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCallFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> {
- const errMessage = await _getContractCallFailedErrorMessageAsync();
- return expect(p).to.be.rejectedWith(errMessage);
-}
-
-/**
- * Resolves if the contract creation/deployment fails without a revert reason.
- * @param p a Promise resulting from a contract creation/deployment
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCreationFailedAsync<T>(
- p: sendTransactionResult,
- reason: RevertReason,
-): Promise<void> {
- return expectTransactionFailedAsync(p, reason);
-}
-
-/**
- * Resolves if the contract creation/deployment fails without a revert reason.
- * @param p a Promise resulting from a contract creation/deployment
- * @returns a new Promise which will reject if the conditions are not met and
- * otherwise resolve with no value.
- */
-export async function expectContractCreationFailedWithoutReasonAsync<T>(p: Promise<T>): Promise<void> {
- const errMessage = await _getTransactionFailedErrorMessageAsync();
- return expect(p).to.be.rejectedWith(errMessage);
-}
diff --git a/packages/contracts/test/utils/asset_wrapper.ts b/packages/contracts/test/utils/asset_wrapper.ts
deleted file mode 100644
index 4e7696066..000000000
--- a/packages/contracts/test/utils/asset_wrapper.ts
+++ /dev/null
@@ -1,223 +0,0 @@
-import { assetDataUtils } from '@0x/order-utils';
-import { AssetProxyId } from '@0x/types';
-import { BigNumber, errorUtils } from '@0x/utils';
-import * as _ from 'lodash';
-
-import { AbstractAssetWrapper } from './abstract_asset_wrapper';
-import { constants } from './constants';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-
-interface ProxyIdToAssetWrappers {
- [proxyId: string]: AbstractAssetWrapper;
-}
-
-/**
- * This class abstracts away the differences between ERC20 and ERC721 tokens so that
- * the logic that uses it does not need to care what standard a token belongs to.
- */
-export class AssetWrapper {
- private readonly _proxyIdToAssetWrappers: ProxyIdToAssetWrappers;
- constructor(assetWrappers: AbstractAssetWrapper[]) {
- this._proxyIdToAssetWrappers = {};
- _.each(assetWrappers, assetWrapper => {
- const proxyId = assetWrapper.getProxyId();
- this._proxyIdToAssetWrappers[proxyId] = assetWrapper;
- });
- }
- public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- const balance = await erc20Wrapper.getBalanceAsync(userAddress, assetData);
- return balance;
- }
- case AssetProxyId.ERC721: {
- const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const assetProxyData = assetDataUtils.decodeERC721AssetData(assetData);
- const isOwner = await assetWrapper.isOwnerAsync(
- userAddress,
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- const balance = isOwner ? new BigNumber(1) : new BigNumber(0);
- return balance;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
- public async setBalanceAsync(userAddress: string, assetData: string, desiredBalance: BigNumber): Promise<void> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- await erc20Wrapper.setBalanceAsync(userAddress, assetData, desiredBalance);
- return;
- }
- case AssetProxyId.ERC721: {
- if (!desiredBalance.eq(0) && !desiredBalance.eq(1)) {
- throw new Error(`Balance for ERC721 token can only be set to 0 or 1. Got: ${desiredBalance}`);
- }
- const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const assetProxyData = assetDataUtils.decodeERC721AssetData(assetData);
- const doesTokenExist = erc721Wrapper.doesTokenExistAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (!doesTokenExist && desiredBalance.eq(1)) {
- await erc721Wrapper.mintAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress);
- return;
- } else if (!doesTokenExist && desiredBalance.eq(0)) {
- return; // noop
- }
- const tokenOwner = await erc721Wrapper.ownerOfAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (userAddress !== tokenOwner && desiredBalance.eq(1)) {
- await erc721Wrapper.transferFromAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- tokenOwner,
- userAddress,
- );
- } else if (tokenOwner === userAddress && desiredBalance.eq(0)) {
- // Transfer token to someone else
- const userAddresses = await (erc721Wrapper as any)._web3Wrapper.getAvailableAddressesAsync();
- const nonOwner = _.find(userAddresses, a => a !== userAddress);
- await erc721Wrapper.transferFromAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- tokenOwner,
- nonOwner,
- );
- return;
- } else if (
- (userAddress !== tokenOwner && desiredBalance.eq(0)) ||
- (tokenOwner === userAddress && desiredBalance.eq(1))
- ) {
- return; // noop
- }
- break;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
- public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- const allowance = await erc20Wrapper.getProxyAllowanceAsync(userAddress, assetData);
- return allowance;
- }
- case AssetProxyId.ERC721: {
- const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const erc721ProxyData = assetDataUtils.decodeERC721AssetData(assetData);
- const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync(
- userAddress,
- erc721ProxyData.tokenAddress,
- );
- if (isProxyApprovedForAll) {
- return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- }
-
- const isProxyApproved = await assetWrapper.isProxyApprovedAsync(
- erc721ProxyData.tokenAddress,
- erc721ProxyData.tokenId,
- );
- const allowance = isProxyApproved ? new BigNumber(1) : new BigNumber(0);
- return allowance;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
- public async setProxyAllowanceAsync(
- userAddress: string,
- assetData: string,
- desiredAllowance: BigNumber,
- ): Promise<void> {
- const proxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (proxyId) {
- case AssetProxyId.ERC20: {
- const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper;
- await erc20Wrapper.setAllowanceAsync(userAddress, assetData, desiredAllowance);
- return;
- }
- case AssetProxyId.ERC721: {
- if (
- !desiredAllowance.eq(0) &&
- !desiredAllowance.eq(1) &&
- !desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)
- ) {
- throw new Error(
- `Allowance for ERC721 token can only be set to 0, 1 or 2^256-1. Got: ${desiredAllowance}`,
- );
- }
- const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper;
- const assetProxyData = assetDataUtils.decodeERC721AssetData(assetData);
-
- const doesTokenExist = await erc721Wrapper.doesTokenExistAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (!doesTokenExist) {
- throw new Error(
- `Cannot setProxyAllowance on non-existent token: ${assetProxyData.tokenAddress} ${
- assetProxyData.tokenId
- }`,
- );
- }
- const isProxyApprovedForAll = await erc721Wrapper.isProxyApprovedForAllAsync(
- userAddress,
- assetProxyData.tokenAddress,
- );
- if (!isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
- const isApproved = true;
- await erc721Wrapper.approveProxyForAllAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- isApproved,
- );
- } else if (isProxyApprovedForAll && desiredAllowance.eq(0)) {
- const isApproved = false;
- await erc721Wrapper.approveProxyForAllAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- isApproved,
- );
- } else if (isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
- return; // Noop
- }
-
- const isProxyApproved = await erc721Wrapper.isProxyApprovedAsync(
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- if (!isProxyApproved && desiredAllowance.eq(1)) {
- await erc721Wrapper.approveProxyAsync(assetProxyData.tokenAddress, assetProxyData.tokenId);
- } else if (isProxyApproved && desiredAllowance.eq(0)) {
- // Remove approval
- await erc721Wrapper.approveAsync(
- constants.NULL_ADDRESS,
- assetProxyData.tokenAddress,
- assetProxyData.tokenId,
- );
- } else if (
- (!isProxyApproved && desiredAllowance.eq(0)) ||
- (isProxyApproved && desiredAllowance.eq(1))
- ) {
- return; // noop
- }
-
- break;
- }
- default:
- throw errorUtils.spawnSwitchErr('proxyId', proxyId);
- }
- }
-}
diff --git a/packages/contracts/test/utils/block_timestamp.ts b/packages/contracts/test/utils/block_timestamp.ts
deleted file mode 100644
index 66c13eed1..000000000
--- a/packages/contracts/test/utils/block_timestamp.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import * as _ from 'lodash';
-
-import { constants } from './constants';
-import { web3Wrapper } from './web3_wrapper';
-
-let firstAccount: string | undefined;
-
-/**
- * Increases time by the given number of seconds and then mines a block so that
- * the current block timestamp has the offset applied.
- * @param seconds the number of seconds by which to incrase the time offset.
- * @returns a new Promise which will resolve with the new total time offset or
- * reject if the time could not be increased.
- */
-export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<number> {
- if (_.isUndefined(firstAccount)) {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- firstAccount = accounts[0];
- }
-
- const offset = await web3Wrapper.increaseTimeAsync(seconds);
- // Note: we need to send a transaction after increasing time so
- // that a block is actually mined. The contract looks at the
- // last mined block for the timestamp.
- await web3Wrapper.awaitTransactionSuccessAsync(
- await web3Wrapper.sendTransactionAsync({ from: firstAccount, to: firstAccount, value: 0 }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- return offset;
-}
-
-/**
- * Returns the timestamp of the latest block in seconds since the Unix epoch.
- * @returns a new Promise which will resolve with the timestamp in seconds.
- */
-export async function getLatestBlockTimestampAsync(): Promise<number> {
- const currentBlockIfExists = await web3Wrapper.getBlockIfExistsAsync('latest');
- if (_.isUndefined(currentBlockIfExists)) {
- throw new Error(`Unable to fetch latest block.`);
- }
- return currentBlockIfExists.timestamp;
-}
diff --git a/packages/contracts/test/utils/combinatorial_utils.ts b/packages/contracts/test/utils/combinatorial_utils.ts
deleted file mode 100644
index bb1b55b4d..000000000
--- a/packages/contracts/test/utils/combinatorial_utils.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as combinatorics from 'js-combinatorics';
-
-import { testWithReferenceFuncAsync } from './test_with_reference';
-
-// A set of values corresponding to the uint256 type in Solidity. This set
-// contains some notable edge cases, including some values which will overflow
-// the uint256 type when used in different mathematical operations.
-export const uint256Values = [
- new BigNumber(0),
- new BigNumber(1),
- new BigNumber(2),
- // Non-trivial big number.
- new BigNumber(2).pow(64),
- // Max that does not overflow when squared.
- new BigNumber(2).pow(128).minus(1),
- // Min that does overflow when squared.
- new BigNumber(2).pow(128),
- // Max that does not overflow when doubled.
- new BigNumber(2).pow(255).minus(1),
- // Min that does overflow when doubled.
- new BigNumber(2).pow(255),
- // Max that does not overflow.
- new BigNumber(2).pow(256).minus(1),
-];
-
-// A set of values corresponding to the bytes32 type in Solidity.
-export const bytes32Values = [
- // Min
- '0x0000000000000000000000000000000000000000000000000000000000000000',
- '0x0000000000000000000000000000000000000000000000000000000000000001',
- '0x0000000000000000000000000000000000000000000000000000000000000002',
- // Non-trivial big number.
- '0x000000000000f000000000000000000000000000000000000000000000000000',
- // Max
- '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
-];
-
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1) => Promise<R>,
- testFunc: (p0: P0, p1: P1) => Promise<R>,
- allValues: [P0[], P1[]],
-): Promise<void>;
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- allValues: [P0[], P1[], P2[]],
-): Promise<void>;
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- allValues: [P0[], P1[], P2[], P3[]],
-): Promise<void>;
-export async function testCombinatoriallyWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>(
- name: string,
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- allValues: [P0[], P1[], P2[], P3[], P4[]],
-): Promise<void>;
-
-/**
- * Uses combinatorics to test the behavior of a test function by comparing it to
- * the expected behavior (defined by a reference function) for a large number of
- * possible input values.
- *
- * First generates test cases by taking the cartesian product of the given
- * values. Each test case is a set of N values corresponding to the N arguments
- * for the test func and the reference func. For each test case, first the
- * reference function will be called to obtain an "expected result", or if the
- * reference function throws/rejects, an "expected error". Next, the test
- * function will be called to obtain an "actual result", or if the test function
- * throws/rejects, an "actual error". Each test case passes if at least one of
- * the following conditions is met:
- *
- * 1) Neither the reference function or the test function throw and the
- * "expected result" equals the "actual result".
- *
- * 2) Both the reference function and the test function throw and the "actual
- * error" message *contains* the "expected error" message.
- *
- * The first test case which does not meet one of these conditions will cause
- * the entire test to fail and this function will throw/reject.
- *
- * @param referenceFuncAsync a reference function implemented in pure
- * JavaScript/TypeScript which accepts N arguments and returns the "expected
- * result" or "expected error" for a given test case.
- * @param testFuncAsync a test function which, e.g., makes a call or sends a
- * transaction to a contract. It accepts the same N arguments returns the
- * "actual result" or "actual error" for a given test case.
- * @param values an array of N arrays. Each inner array is a set of possible
- * values which are passed into both the reference function and the test
- * function.
- * @return A Promise that resolves if the test passes and rejects if the test
- * fails, according to the rules described above.
- */
-export async function testCombinatoriallyWithReferenceFuncAsync(
- name: string,
- referenceFuncAsync: (...args: any[]) => Promise<any>,
- testFuncAsync: (...args: any[]) => Promise<any>,
- allValues: any[],
-): Promise<void> {
- const testCases = combinatorics.cartesianProduct(...allValues);
- let counter = 0;
- testCases.forEach(async testCase => {
- counter += 1;
- it(`${name} ${counter}/${testCases.length}`, async () => {
- await testWithReferenceFuncAsync(referenceFuncAsync, testFuncAsync, testCase as any);
- });
- });
-}
diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts
deleted file mode 100644
index cd21330e9..000000000
--- a/packages/contracts/test/utils/constants.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as ethUtil from 'ethereumjs-util';
-import * as _ from 'lodash';
-
-const TESTRPC_PRIVATE_KEYS_STRINGS = [
- '0xf2f48ee19680706196e2e339e5da3491186e0c4c5030670656b0e0164837257d',
- '0x5d862464fe9303452126c8bc94274b8c5f9874cbd219789b3eb2128075a76f72',
- '0xdf02719c4df8b9b8ac7f551fcb5d9ef48fa27eef7a66453879f4d8fdc6e78fb1',
- '0xff12e391b79415e941a94de3bf3a9aee577aed0731e297d5cfa0b8a1e02fa1d0',
- '0x752dd9cf65e68cfaba7d60225cbdbc1f4729dd5e5507def72815ed0d8abc6249',
- '0xefb595a0178eb79a8df953f87c5148402a224cdf725e88c0146727c6aceadccd',
- '0x83c6d2cc5ddcf9711a6d59b417dc20eb48afd58d45290099e5987e3d768f328f',
- '0xbb2d3f7c9583780a7d3904a2f55d792707c345f21de1bacb2d389934d82796b2',
- '0xb2fd4d29c1390b71b8795ae81196bfd60293adf99f9d32a0aff06288fcdac55f',
- '0x23cb7121166b9a2f93ae0b7c05bde02eae50d64449b2cbb42bc84e9d38d6cc89',
-];
-
-export const constants = {
- BASE_16: 16,
- INVALID_OPCODE: 'invalid opcode',
- TESTRPC_NETWORK_ID: 50,
- // Note(albrow): In practice V8 and most other engines limit the minimum
- // interval for setInterval to 10ms. We still set it to 0 here in order to
- // ensure we always use the minimum interval.
- AWAIT_TRANSACTION_MINED_MS: 0,
- MAX_ETHERTOKEN_WITHDRAW_GAS: 43000,
- MAX_EXECUTE_TRANSACTION_GAS: 1000000,
- MAX_TOKEN_TRANSFERFROM_GAS: 80000,
- MAX_TOKEN_APPROVE_GAS: 60000,
- MAX_TRANSFER_FROM_GAS: 150000,
- DUMMY_TOKEN_NAME: '',
- DUMMY_TOKEN_SYMBOL: '',
- DUMMY_TOKEN_DECIMALS: new BigNumber(18),
- DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(0),
- NULL_BYTES: '0x',
- NUM_DUMMY_ERC20_TO_DEPLOY: 3,
- NUM_DUMMY_ERC721_TO_DEPLOY: 1,
- NUM_ERC721_TOKENS_TO_MINT: 2,
- NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
- UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
- TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)),
- INITIAL_ERC20_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18),
- INITIAL_ERC20_ALLOWANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18),
- STATIC_ORDER_PARAMS: {
- makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
- takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
- makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
- },
- WORD_LENGTH: 32,
- ZERO_AMOUNT: new BigNumber(0),
- PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18),
- FUNCTIONS_WITH_MUTEX: [
- 'FILL_ORDER',
- 'FILL_OR_KILL_ORDER',
- 'BATCH_FILL_ORDERS',
- 'BATCH_FILL_OR_KILL_ORDERS',
- 'MARKET_BUY_ORDERS',
- 'MARKET_SELL_ORDERS',
- 'MATCH_ORDERS',
- 'CANCEL_ORDER',
- 'BATCH_CANCEL_ORDERS',
- 'CANCEL_ORDERS_UP_TO',
- 'SET_SIGNATURE_VALIDATOR_APPROVAL',
- ],
-};
diff --git a/packages/contracts/test/utils/coverage.ts b/packages/contracts/test/utils/coverage.ts
deleted file mode 100644
index 5becfa1b6..000000000
--- a/packages/contracts/test/utils/coverage.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { devConstants } from '@0x/dev-utils';
-import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov';
-import * as _ from 'lodash';
-
-let coverageSubprovider: CoverageSubprovider;
-
-export const coverage = {
- getCoverageSubproviderSingleton(): CoverageSubprovider {
- if (_.isUndefined(coverageSubprovider)) {
- coverageSubprovider = coverage._getCoverageSubprovider();
- }
- return coverageSubprovider;
- },
- _getCoverageSubprovider(): CoverageSubprovider {
- const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
- const isVerbose = true;
- const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
- return subprovider;
- },
-};
diff --git a/packages/contracts/test/utils/erc20_wrapper.ts b/packages/contracts/test/utils/erc20_wrapper.ts
deleted file mode 100644
index c281a2abf..000000000
--- a/packages/contracts/test/utils/erc20_wrapper.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-import { assetDataUtils } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
-import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
-import { artifacts } from '../../src/artifacts';
-
-import { constants } from './constants';
-import { ERC20BalancesByOwner } from './types';
-import { txDefaults } from './web3_wrapper';
-
-export class ERC20Wrapper {
- private readonly _tokenOwnerAddresses: string[];
- private readonly _contractOwnerAddress: string;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _provider: Provider;
- private readonly _dummyTokenContracts: DummyERC20TokenContract[];
- private _proxyContract?: ERC20ProxyContract;
- private _proxyIdIfExists?: string;
- /**
- * Instanitates an ERC20Wrapper
- * @param provider Web3 provider to use for all JSON RPC requests
- * @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens
- * @param contractOwnerAddress Desired owner of the contract
- * Instance of ERC20Wrapper
- */
- constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
- this._dummyTokenContracts = [];
- this._web3Wrapper = new Web3Wrapper(provider);
- this._provider = provider;
- this._tokenOwnerAddresses = tokenOwnerAddresses;
- this._contractOwnerAddress = contractOwnerAddress;
- }
- public async deployDummyTokensAsync(
- numberToDeploy: number,
- decimals: BigNumber,
- ): Promise<DummyERC20TokenContract[]> {
- for (let i = 0; i < numberToDeploy; i++) {
- this._dummyTokenContracts.push(
- await DummyERC20TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC20Token,
- this._provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- decimals,
- constants.DUMMY_TOKEN_TOTAL_SUPPLY,
- ),
- );
- }
- return this._dummyTokenContracts;
- }
- public async deployProxyAsync(): Promise<ERC20ProxyContract> {
- this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC20Proxy,
- this._provider,
- txDefaults,
- );
- this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
- return this._proxyContract;
- }
- public getProxyId(): string {
- this._validateProxyContractExistsOrThrow();
- return this._proxyIdIfExists as string;
- }
- public async setBalancesAndAllowancesAsync(): Promise<void> {
- this._validateDummyTokenContractsExistOrThrow();
- this._validateProxyContractExistsOrThrow();
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await dummyTokenContract.setBalance.sendTransactionAsync(
- tokenOwnerAddress,
- constants.INITIAL_ERC20_BALANCE,
- { from: this._contractOwnerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await dummyTokenContract.approve.sendTransactionAsync(
- (this._proxyContract as ERC20ProxyContract).address,
- constants.INITIAL_ERC20_ALLOWANCE,
- { from: tokenOwnerAddress },
- ),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- }
- }
- public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress));
- return balance;
- }
- public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.setBalance.sendTransactionAsync(userAddress, amount, {
- from: this._contractOwnerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
- const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress));
- return allowance;
- }
- public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(assetData);
- const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.approve.sendTransactionAsync(proxyAddress, amount, {
- from: userAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
- this._validateDummyTokenContractsExistOrThrow();
- const balancesByOwner: ERC20BalancesByOwner = {};
- const balances: BigNumber[] = [];
- const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress));
- balanceInfo.push({
- tokenOwnerAddress,
- tokenAddress: dummyTokenContract.address,
- });
- }
- }
- _.forEach(balances, (balance, balanceIndex) => {
- const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
- const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
- if (_.isUndefined(balancesByOwner[tokenOwnerAddress])) {
- balancesByOwner[tokenOwnerAddress] = {};
- }
- const wrappedBalance = new BigNumber(balance);
- balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance;
- });
- return balancesByOwner;
- }
- public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
- if (!_.isUndefined(this._dummyTokenContracts)) {
- this._dummyTokenContracts.push(dummy);
- }
- }
- public addTokenOwnerAddress(address: string): void {
- this._tokenOwnerAddresses.push(address);
- }
- public getTokenOwnerAddresses(): string[] {
- return this._tokenOwnerAddresses;
- }
- public getTokenAddresses(): string[] {
- const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
- return tokenAddresses;
- }
- private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract {
- const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData);
- const tokenAddress = erc20ProxyData.tokenAddress;
- const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
- if (_.isUndefined(tokenContractIfExists)) {
- throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
- }
- return tokenContractIfExists;
- }
- private _validateDummyTokenContractsExistOrThrow(): void {
- if (_.isUndefined(this._dummyTokenContracts)) {
- throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
- }
- }
- private _validateProxyContractExistsOrThrow(): void {
- if (_.isUndefined(this._proxyContract)) {
- throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
- }
- }
-}
diff --git a/packages/contracts/test/utils/erc721_wrapper.ts b/packages/contracts/test/utils/erc721_wrapper.ts
deleted file mode 100644
index 3ef4e701d..000000000
--- a/packages/contracts/test/utils/erc721_wrapper.ts
+++ /dev/null
@@ -1,237 +0,0 @@
-import { generatePseudoRandomSalt } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
-import { artifacts } from '../../src/artifacts';
-
-import { constants } from './constants';
-import { ERC721TokenIdsByOwner } from './types';
-import { txDefaults } from './web3_wrapper';
-
-export class ERC721Wrapper {
- private readonly _tokenOwnerAddresses: string[];
- private readonly _contractOwnerAddress: string;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _provider: Provider;
- private readonly _dummyTokenContracts: DummyERC721TokenContract[];
- private _proxyContract?: ERC721ProxyContract;
- private _proxyIdIfExists?: string;
- private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
- constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
- this._web3Wrapper = new Web3Wrapper(provider);
- this._provider = provider;
- this._dummyTokenContracts = [];
- this._tokenOwnerAddresses = tokenOwnerAddresses;
- this._contractOwnerAddress = contractOwnerAddress;
- }
- public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
- for (let i = 0; i < constants.NUM_DUMMY_ERC721_TO_DEPLOY; i++) {
- this._dummyTokenContracts.push(
- await DummyERC721TokenContract.deployFrom0xArtifactAsync(
- artifacts.DummyERC721Token,
- this._provider,
- txDefaults,
- constants.DUMMY_TOKEN_NAME,
- constants.DUMMY_TOKEN_SYMBOL,
- ),
- );
- }
- return this._dummyTokenContracts;
- }
- public async deployProxyAsync(): Promise<ERC721ProxyContract> {
- this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync(
- artifacts.ERC721Proxy,
- this._provider,
- txDefaults,
- );
- this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
- return this._proxyContract;
- }
- public getProxyId(): string {
- this._validateProxyContractExistsOrThrow();
- return this._proxyIdIfExists as string;
- }
- public async setBalancesAndAllowancesAsync(): Promise<void> {
- this._validateDummyTokenContractsExistOrThrow();
- this._validateProxyContractExistsOrThrow();
- 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++) {
- const tokenId = generatePseudoRandomSalt();
- await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
- if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) {
- this._initialTokenIdsByOwner[tokenOwnerAddress] = {
- [dummyTokenContract.address]: [],
- };
- }
- if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address])) {
- this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
- }
- this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
-
- await this.approveProxyAsync(dummyTokenContract.address, tokenId);
- }
- }
- }
- }
- public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const owner = await tokenContract.ownerOf.callAsync(tokenId);
- const doesExist = owner !== constants.NULL_ADDRESS;
- return doesExist;
- }
- public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> {
- const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
- await this.approveAsync(proxyAddress, tokenAddress, tokenId);
- }
- public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
- const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.setApprovalForAll.sendTransactionAsync(proxyAddress, isApproved, {
- from: tokenOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.approve.sendTransactionAsync(to, tokenId, {
- from: tokenOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async transferFromAsync(
- tokenAddress: string,
- tokenId: BigNumber,
- currentOwner: string,
- userAddress: string,
- ): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.transferFrom.sendTransactionAsync(currentOwner, userAddress, tokenId, {
- from: currentOwner,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.mint.sendTransactionAsync(userAddress, tokenId, {
- from: this._contractOwnerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- await this._web3Wrapper.awaitTransactionSuccessAsync(
- await tokenContract.burn.sendTransactionAsync(owner, tokenId, {
- from: this._contractOwnerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- }
- public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const owner = await tokenContract.ownerOf.callAsync(tokenId);
- return owner;
- }
- public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId);
- const isOwner = tokenOwner === userAddress;
- return isOwner;
- }
- public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> {
- this._validateProxyContractExistsOrThrow();
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const operator = (this._proxyContract as ERC721ProxyContract).address;
- const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
- return didApproveAll;
- }
- public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
- this._validateProxyContractExistsOrThrow();
- const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
- const approvedAddress = await tokenContract.getApproved.callAsync(tokenId);
- const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
- const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
- return isProxyAnApprovedOperator;
- }
- public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> {
- this._validateDummyTokenContractsExistOrThrow();
- this._validateBalancesAndAllowancesSetOrThrow();
- const tokenIdsByOwner: ERC721TokenIdsByOwner = {};
- const tokenOwnerAddresses: string[] = [];
- const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = [];
- for (const dummyTokenContract of this._dummyTokenContracts) {
- for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
- const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][
- dummyTokenContract.address
- ];
- for (const tokenId of initialTokenOwnerIds) {
- tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId));
- tokenInfo.push({
- tokenId,
- tokenAddress: dummyTokenContract.address,
- });
- }
- }
- }
- _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
- const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
- const tokenId = tokenInfo[ownerIndex].tokenId;
- if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress])) {
- tokenIdsByOwner[tokenOwnerAddress] = {
- [tokenAddress]: [],
- };
- }
- if (_.isUndefined(tokenIdsByOwner[tokenOwnerAddress][tokenAddress])) {
- tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
- }
- tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
- });
- return tokenIdsByOwner;
- }
- public getTokenOwnerAddresses(): string[] {
- return this._tokenOwnerAddresses;
- }
- public getTokenAddresses(): string[] {
- const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
- return tokenAddresses;
- }
- private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
- const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
- if (_.isUndefined(tokenContractIfExists)) {
- throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
- }
- return tokenContractIfExists;
- }
- private _validateDummyTokenContractsExistOrThrow(): void {
- if (_.isUndefined(this._dummyTokenContracts)) {
- throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
- }
- }
- private _validateProxyContractExistsOrThrow(): void {
- if (_.isUndefined(this._proxyContract)) {
- throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
- }
- }
- private _validateBalancesAndAllowancesSetOrThrow(): void {
- if (_.keys(this._initialTokenIdsByOwner).length === 0) {
- throw new Error(
- 'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
- );
- }
- }
-}
diff --git a/packages/contracts/test/utils/exchange_wrapper.ts b/packages/contracts/test/utils/exchange_wrapper.ts
deleted file mode 100644
index c28989d3f..000000000
--- a/packages/contracts/test/utils/exchange_wrapper.ts
+++ /dev/null
@@ -1,276 +0,0 @@
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-
-import { ExchangeContract } from '../../generated-wrappers/exchange';
-
-import { formatters } from './formatters';
-import { LogDecoder } from './log_decoder';
-import { orderUtils } from './order_utils';
-import { FillResults, OrderInfo, SignedTransaction } from './types';
-
-export class ExchangeWrapper {
- private readonly _exchange: ExchangeContract;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _logDecoder: LogDecoder;
- constructor(exchangeContract: ExchangeContract, provider: Provider) {
- this._exchange = exchangeContract;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper);
- }
- public async fillOrderAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const txHash = await this._exchange.fillOrder.sendTransactionAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from },
- );
- const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return txReceipt;
- }
- public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createCancel(signedOrder);
- const txHash = await this._exchange.cancelOrder.sendTransactionAsync(params.order, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async fillOrKillOrderAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const txHash = await this._exchange.fillOrKillOrder.sendTransactionAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async fillOrderNoThrowAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const txHash = await this._exchange.fillOrderNoThrow.sendTransactionAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchFillOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[] } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const txHash = await this._exchange.batchFillOrders.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchFillOrKillOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[] } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const txHash = await this._exchange.batchFillOrKillOrders.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchFillOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
- const txHash = await this._exchange.batchFillOrdersNoThrow.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmounts,
- params.signatures,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketSellOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmount: BigNumber },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
- const txHash = await this._exchange.marketSellOrders.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmount,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketSellOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { takerAssetFillAmount: BigNumber; gas?: number },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
- const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync(
- params.orders,
- params.takerAssetFillAmount,
- params.signatures,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketBuyOrdersAsync(
- orders: SignedOrder[],
- from: string,
- opts: { makerAssetFillAmount: BigNumber },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
- const txHash = await this._exchange.marketBuyOrders.sendTransactionAsync(
- params.orders,
- params.makerAssetFillAmount,
- params.signatures,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketBuyOrdersNoThrowAsync(
- orders: SignedOrder[],
- from: string,
- opts: { makerAssetFillAmount: BigNumber; gas?: number },
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
- const txHash = await this._exchange.marketBuyOrdersNoThrow.sendTransactionAsync(
- params.orders,
- params.makerAssetFillAmount,
- params.signatures,
- { from, gas: opts.gas },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async batchCancelOrdersAsync(
- orders: SignedOrder[],
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = formatters.createBatchCancel(orders);
- const txHash = await this._exchange.batchCancelOrders.sendTransactionAsync(params.orders, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._exchange.cancelOrdersUpTo.sendTransactionAsync(salt, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async registerAssetProxyAsync(
- assetProxyAddress: string,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._exchange.registerAssetProxy.sendTransactionAsync(assetProxyAddress, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async executeTransactionAsync(
- signedTx: SignedTransaction,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._exchange.executeTransaction.sendTransactionAsync(
- signedTx.salt,
- signedTx.signerAddress,
- signedTx.data,
- signedTx.signature,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
- const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
- return filledAmount;
- }
- public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
- const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
- return isCancelled;
- }
- public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
- const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
- return orderEpoch;
- }
- public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
- const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo;
- return orderInfo;
- }
- public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
- const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
- return ordersInfo;
- }
- public async matchOrdersAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
- const txHash = await this._exchange.matchOrders.sendTransactionAsync(
- params.left,
- params.right,
- params.leftSignature,
- params.rightSignature,
- { from },
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async getFillOrderResultsAsync(
- signedOrder: SignedOrder,
- from: string,
- opts: { takerAssetFillAmount?: BigNumber } = {},
- ): Promise<FillResults> {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const fillResults = await this._exchange.fillOrder.callAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- { from },
- );
- return fillResults;
- }
- public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
- const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
- const data = this._exchange.fillOrder.getABIEncodedTransactionData(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- return data;
- }
- public getExchangeAddress(): string {
- return this._exchange.address;
- }
-}
diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
deleted file mode 100644
index 8046771f9..000000000
--- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
+++ /dev/null
@@ -1,924 +0,0 @@
-import {
- assetDataUtils,
- BalanceAndProxyAllowanceLazyStore,
- ExchangeTransferSimulator,
- orderHashUtils,
- OrderStateUtils,
- OrderValidationUtils,
-} from '@0x/order-utils';
-import { AssetProxyId, RevertReason, SignatureType, SignedOrder } from '@0x/types';
-import { BigNumber, errorUtils, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import { LogWithDecodedArgs, Provider, TxData } from 'ethereum-types';
-import * as _ from 'lodash';
-import 'make-promises-safe';
-
-import { ExchangeContract, ExchangeFillEventArgs } from '../../generated-wrappers/exchange';
-import { TestLibsContract } from '../../generated-wrappers/test_libs';
-import { artifacts } from '../../src/artifacts';
-
-import { expectTransactionFailedAsync } from './assertions';
-import { AssetWrapper } from './asset_wrapper';
-import { chaiSetup } from './chai_setup';
-import { constants } from './constants';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-import { ExchangeWrapper } from './exchange_wrapper';
-import { OrderFactoryFromScenario } from './order_factory_from_scenario';
-import { orderUtils } from './order_utils';
-import { signingUtils } from './signing_utils';
-import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher';
-import { SimpleOrderFilledCancelledFetcher } from './simple_order_filled_cancelled_fetcher';
-import {
- AllowanceAmountScenario,
- AssetDataScenario,
- BalanceAmountScenario,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- FillScenario,
- OrderAssetAmountScenario,
- TakerAssetFillAmountScenario,
- TakerScenario,
- TraderStateScenario,
-} from './types';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-/**
- * Instantiates a new instance of FillOrderCombinatorialUtils. Since this method has some
- * required async setup, a factory method is required.
- * @param web3Wrapper Web3Wrapper instance
- * @param txDefaults Default Ethereum tx options
- * @return FillOrderCombinatorialUtils instance
- */
-export async function fillOrderCombinatorialUtilsFactoryAsync(
- web3Wrapper: Web3Wrapper,
- txDefaults: Partial<TxData>,
-): Promise<FillOrderCombinatorialUtils> {
- const accounts = await web3Wrapper.getAvailableAddressesAsync();
- const userAddresses = _.slice(accounts, 0, 5);
- const [ownerAddress, makerAddress, takerAddress] = userAddresses;
- const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(makerAddress)];
-
- const provider = web3Wrapper.getProvider();
- const erc20Wrapper = new ERC20Wrapper(provider, userAddresses, ownerAddress);
- const erc721Wrapper = new ERC721Wrapper(provider, userAddresses, ownerAddress);
-
- const erc20EighteenDecimalTokenCount = 3;
- const eighteenDecimals = new BigNumber(18);
- const [
- erc20EighteenDecimalTokenA,
- erc20EighteenDecimalTokenB,
- zrxToken,
- ] = await erc20Wrapper.deployDummyTokensAsync(erc20EighteenDecimalTokenCount, eighteenDecimals);
- const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
-
- const erc20FiveDecimalTokenCount = 2;
- const fiveDecimals = new BigNumber(5);
- const [erc20FiveDecimalTokenA, erc20FiveDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
- erc20FiveDecimalTokenCount,
- fiveDecimals,
- );
- const zeroDecimals = new BigNumber(0);
- const erc20ZeroDecimalTokenCount = 2;
- const [erc20ZeroDecimalTokenA, erc20ZeroDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
- erc20ZeroDecimalTokenCount,
- zeroDecimals,
- );
- const erc20Proxy = await erc20Wrapper.deployProxyAsync();
- await erc20Wrapper.setBalancesAndAllowancesAsync();
-
- const [erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
- const erc721Proxy = await erc721Wrapper.deployProxyAsync();
- await erc721Wrapper.setBalancesAndAllowancesAsync();
- const erc721Balances = await erc721Wrapper.getBalancesAsync();
-
- const assetWrapper = new AssetWrapper([erc20Wrapper, erc721Wrapper]);
-
- const exchangeContract = await ExchangeContract.deployFrom0xArtifactAsync(
- artifacts.Exchange,
- provider,
- txDefaults,
- zrxAssetData,
- );
- const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider);
- await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress);
- await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, ownerAddress);
-
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
- from: ownerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
- await web3Wrapper.awaitTransactionSuccessAsync(
- await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
- from: ownerAddress,
- }),
- constants.AWAIT_TRANSACTION_MINED_MS,
- );
-
- const orderFactory = new OrderFactoryFromScenario(
- userAddresses,
- zrxToken.address,
- [erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address],
- [erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address],
- [erc20ZeroDecimalTokenA.address, erc20ZeroDecimalTokenB.address],
- erc721Token,
- erc721Balances,
- exchangeContract.address,
- );
-
- const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
-
- const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils(
- orderFactory,
- ownerAddress,
- makerAddress,
- makerPrivateKey,
- takerAddress,
- zrxAssetData,
- exchangeWrapper,
- assetWrapper,
- testLibsContract,
- );
- return fillOrderCombinatorialUtils;
-}
-
-export class FillOrderCombinatorialUtils {
- public orderFactory: OrderFactoryFromScenario;
- public ownerAddress: string;
- public makerAddress: string;
- public makerPrivateKey: Buffer;
- public takerAddress: string;
- public zrxAssetData: string;
- public exchangeWrapper: ExchangeWrapper;
- public assetWrapper: AssetWrapper;
- public testLibsContract: TestLibsContract;
- public static generateFillOrderCombinations(): FillScenario[] {
- const takerScenarios = [
- TakerScenario.Unspecified,
- // TakerScenario.CorrectlySpecified,
- // TakerScenario.IncorrectlySpecified,
- ];
- const feeRecipientScenarios = [
- FeeRecipientAddressScenario.EthUserAddress,
- // FeeRecipientAddressScenario.BurnAddress,
- ];
- const makerAssetAmountScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Zero,
- // OrderAssetAmountScenario.Small,
- ];
- const takerAssetAmountScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Zero,
- // OrderAssetAmountScenario.Small,
- ];
- const makerFeeScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Small,
- // OrderAssetAmountScenario.Zero,
- ];
- const takerFeeScenario = [
- OrderAssetAmountScenario.Large,
- // OrderAssetAmountScenario.Small,
- // OrderAssetAmountScenario.Zero,
- ];
- const expirationTimeSecondsScenario = [
- ExpirationTimeSecondsScenario.InFuture,
- ExpirationTimeSecondsScenario.InPast,
- ];
- const makerAssetDataScenario = [
- AssetDataScenario.ERC20FiveDecimals,
- AssetDataScenario.ERC20NonZRXEighteenDecimals,
- AssetDataScenario.ERC721,
- AssetDataScenario.ZRXFeeToken,
- ];
- const takerAssetDataScenario = [
- AssetDataScenario.ERC20FiveDecimals,
- AssetDataScenario.ERC20NonZRXEighteenDecimals,
- AssetDataScenario.ERC721,
- AssetDataScenario.ZRXFeeToken,
- ];
- const takerAssetFillAmountScenario = [
- TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
- // TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
- // TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
- ];
- const makerAssetBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const makerAssetAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const makerZRXBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const makerZRXAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const takerAssetBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const takerAssetAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const takerZRXBalanceScenario = [
- BalanceAmountScenario.Higher,
- // BalanceAmountScenario.Exact,
- // BalanceAmountScenario.TooLow,
- ];
- const takerZRXAllowanceScenario = [
- AllowanceAmountScenario.Higher,
- // AllowanceAmountScenario.Exact,
- // AllowanceAmountScenario.TooLow,
- // AllowanceAmountScenario.Unlimited,
- ];
- const fillScenarioArrays = FillOrderCombinatorialUtils._getAllCombinations([
- takerScenarios,
- feeRecipientScenarios,
- makerAssetAmountScenario,
- takerAssetAmountScenario,
- makerFeeScenario,
- takerFeeScenario,
- expirationTimeSecondsScenario,
- makerAssetDataScenario,
- takerAssetDataScenario,
- takerAssetFillAmountScenario,
- makerAssetBalanceScenario,
- makerAssetAllowanceScenario,
- makerZRXBalanceScenario,
- makerZRXAllowanceScenario,
- takerAssetBalanceScenario,
- takerAssetAllowanceScenario,
- takerZRXBalanceScenario,
- takerZRXAllowanceScenario,
- ]);
-
- const fillScenarios = _.map(fillScenarioArrays, fillScenarioArray => {
- // tslint:disable:custom-no-magic-numbers
- const fillScenario: FillScenario = {
- orderScenario: {
- takerScenario: fillScenarioArray[0] as TakerScenario,
- feeRecipientScenario: fillScenarioArray[1] as FeeRecipientAddressScenario,
- makerAssetAmountScenario: fillScenarioArray[2] as OrderAssetAmountScenario,
- takerAssetAmountScenario: fillScenarioArray[3] as OrderAssetAmountScenario,
- makerFeeScenario: fillScenarioArray[4] as OrderAssetAmountScenario,
- takerFeeScenario: fillScenarioArray[5] as OrderAssetAmountScenario,
- expirationTimeSecondsScenario: fillScenarioArray[6] as ExpirationTimeSecondsScenario,
- makerAssetDataScenario: fillScenarioArray[7] as AssetDataScenario,
- takerAssetDataScenario: fillScenarioArray[8] as AssetDataScenario,
- },
- takerAssetFillAmountScenario: fillScenarioArray[9] as TakerAssetFillAmountScenario,
- makerStateScenario: {
- traderAssetBalance: fillScenarioArray[10] as BalanceAmountScenario,
- traderAssetAllowance: fillScenarioArray[11] as AllowanceAmountScenario,
- zrxFeeBalance: fillScenarioArray[12] as BalanceAmountScenario,
- zrxFeeAllowance: fillScenarioArray[13] as AllowanceAmountScenario,
- },
- takerStateScenario: {
- traderAssetBalance: fillScenarioArray[14] as BalanceAmountScenario,
- traderAssetAllowance: fillScenarioArray[15] as AllowanceAmountScenario,
- zrxFeeBalance: fillScenarioArray[16] as BalanceAmountScenario,
- zrxFeeAllowance: fillScenarioArray[17] as AllowanceAmountScenario,
- },
- };
- // tslint:enable:custom-no-magic-numbers
- return fillScenario;
- });
-
- return fillScenarios;
- }
- /**
- * Recursive implementation of generating all combinations of the supplied
- * string-containing arrays.
- */
- private static _getAllCombinations(arrays: string[][]): string[][] {
- // Base case
- if (arrays.length === 1) {
- const remainingValues = _.map(arrays[0], val => {
- return [val];
- });
- return remainingValues;
- } else {
- const result = [];
- const restOfArrays = arrays.slice(1);
- const allCombinationsOfRemaining = FillOrderCombinatorialUtils._getAllCombinations(restOfArrays); // recur with the rest of array
- // tslint:disable:prefer-for-of
- for (let i = 0; i < allCombinationsOfRemaining.length; i++) {
- for (let j = 0; j < arrays[0].length; j++) {
- result.push([arrays[0][j], ...allCombinationsOfRemaining[i]]);
- }
- }
- // tslint:enable:prefer-for-of
- return result;
- }
- }
- constructor(
- orderFactory: OrderFactoryFromScenario,
- ownerAddress: string,
- makerAddress: string,
- makerPrivateKey: Buffer,
- takerAddress: string,
- zrxAssetData: string,
- exchangeWrapper: ExchangeWrapper,
- assetWrapper: AssetWrapper,
- testLibsContract: TestLibsContract,
- ) {
- this.orderFactory = orderFactory;
- this.ownerAddress = ownerAddress;
- this.makerAddress = makerAddress;
- this.makerPrivateKey = makerPrivateKey;
- this.takerAddress = takerAddress;
- this.zrxAssetData = zrxAssetData;
- this.exchangeWrapper = exchangeWrapper;
- this.assetWrapper = assetWrapper;
- this.testLibsContract = testLibsContract;
- }
- public async testFillOrderScenarioAsync(
- provider: Provider,
- fillScenario: FillScenario,
- isVerbose: boolean = false,
- ): Promise<void> {
- // 1. Generate order
- const order = this.orderFactory.generateOrder(fillScenario.orderScenario);
-
- // 2. Sign order
- const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
- const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign);
- const signedOrder = {
- ...order,
- signature: `0x${signature.toString('hex')}`,
- };
-
- const balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(this.assetWrapper);
- const orderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(
- this.exchangeWrapper,
- this.zrxAssetData,
- );
-
- // 3. Figure out fill amount
- const takerAssetFillAmount = await this._getTakerAssetFillAmountAsync(
- signedOrder,
- fillScenario.takerAssetFillAmountScenario,
- balanceAndProxyAllowanceFetcher,
- orderFilledCancelledFetcher,
- );
-
- // 4. Permutate the maker and taker balance/allowance scenarios
- await this._modifyTraderStateAsync(
- fillScenario.makerStateScenario,
- fillScenario.takerStateScenario,
- signedOrder,
- takerAssetFillAmount,
- );
-
- // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected?
- const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher, provider);
- const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher);
- const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore);
-
- let fillRevertReasonIfExists;
- try {
- await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTransferSimulator,
- provider,
- signedOrder,
- takerAssetFillAmount,
- this.takerAddress,
- this.zrxAssetData,
- );
- if (isVerbose) {
- logUtils.log(`Expecting fillOrder to succeed.`);
- }
- } catch (err) {
- fillRevertReasonIfExists = err.message;
- if (isVerbose) {
- logUtils.log(`Expecting fillOrder to fail with:`);
- logUtils.log(err);
- }
- }
-
- // 6. Fill the order
- await this._fillOrderAndAssertOutcomeAsync(
- signedOrder,
- takerAssetFillAmount,
- lazyStore,
- fillRevertReasonIfExists,
- );
-
- await this._abiEncodeFillOrderAndAssertOutcomeAsync(signedOrder, takerAssetFillAmount);
- }
- private async _fillOrderAndAssertOutcomeAsync(
- signedOrder: SignedOrder,
- takerAssetFillAmount: BigNumber,
- lazyStore: BalanceAndProxyAllowanceLazyStore,
- fillRevertReasonIfExists: RevertReason | undefined,
- ): Promise<void> {
- if (!_.isUndefined(fillRevertReasonIfExists)) {
- return expectTransactionFailedAsync(
- this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }),
- fillRevertReasonIfExists,
- );
- }
-
- const makerAddress = signedOrder.makerAddress;
- const makerAssetData = signedOrder.makerAssetData;
- const takerAssetData = signedOrder.takerAssetData;
- const feeRecipient = signedOrder.feeRecipientAddress;
-
- const expMakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(makerAssetData, makerAddress);
- const expMakerAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(makerAssetData, makerAddress);
- const expTakerAssetBalanceOfMaker = await lazyStore.getBalanceAsync(takerAssetData, makerAddress);
- const expZRXAssetBalanceOfMaker = await lazyStore.getBalanceAsync(this.zrxAssetData, makerAddress);
- const expZRXAssetAllowanceOfMaker = await lazyStore.getProxyAllowanceAsync(this.zrxAssetData, makerAddress);
- const expTakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(takerAssetData, this.takerAddress);
- const expTakerAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(takerAssetData, this.takerAddress);
- const expMakerAssetBalanceOfTaker = await lazyStore.getBalanceAsync(makerAssetData, this.takerAddress);
- const expZRXAssetBalanceOfTaker = await lazyStore.getBalanceAsync(this.zrxAssetData, this.takerAddress);
- const expZRXAssetAllowanceOfTaker = await lazyStore.getProxyAllowanceAsync(
- this.zrxAssetData,
- this.takerAddress,
- );
- const expZRXAssetBalanceOfFeeRecipient = await lazyStore.getBalanceAsync(this.zrxAssetData, feeRecipient);
-
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const alreadyFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash);
- const remainingTakerAmountToFill = signedOrder.takerAssetAmount.minus(alreadyFilledTakerAmount);
- const expFilledTakerAmount = takerAssetFillAmount.gt(remainingTakerAmountToFill)
- ? remainingTakerAmountToFill
- : alreadyFilledTakerAmount.add(takerAssetFillAmount);
-
- const expFilledMakerAmount = orderUtils.getPartialAmountFloor(
- expFilledTakerAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerAssetAmount,
- );
- const expMakerFeePaid = orderUtils.getPartialAmountFloor(
- expFilledTakerAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerFee,
- );
- const expTakerFeePaid = orderUtils.getPartialAmountFloor(
- expFilledTakerAmount,
- signedOrder.takerAssetAmount,
- signedOrder.takerFee,
- );
- const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, {
- takerAssetFillAmount,
- });
- expect(fillResults.takerAssetFilledAmount).to.be.bignumber.equal(
- expFilledTakerAmount,
- 'takerAssetFilledAmount',
- );
- expect(fillResults.makerAssetFilledAmount).to.be.bignumber.equal(
- expFilledMakerAmount,
- 'makerAssetFilledAmount',
- );
- expect(fillResults.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'takerFeePaid');
- expect(fillResults.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'makerFeePaid');
-
- // - Let's fill the order!
- const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, {
- takerAssetFillAmount,
- });
-
- const actFilledTakerAmount = await this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash);
- expect(actFilledTakerAmount).to.be.bignumber.equal(expFilledTakerAmount, 'filledTakerAmount');
-
- const exchangeLogs = _.filter(
- txReceipt.logs,
- txLog => txLog.address === this.exchangeWrapper.getExchangeAddress(),
- );
- expect(exchangeLogs.length).to.be.equal(1, 'logs length');
- // tslint:disable-next-line:no-unnecessary-type-assertion
- const log = txReceipt.logs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>;
- expect(log.args.makerAddress).to.be.equal(makerAddress, 'log.args.makerAddress');
- expect(log.args.takerAddress).to.be.equal(this.takerAddress, 'log.args.this.takerAddress');
- expect(log.args.feeRecipientAddress).to.be.equal(feeRecipient, 'log.args.feeRecipientAddress');
- expect(log.args.makerAssetFilledAmount).to.be.bignumber.equal(
- expFilledMakerAmount,
- 'log.args.makerAssetFilledAmount',
- );
- expect(log.args.takerAssetFilledAmount).to.be.bignumber.equal(
- expFilledTakerAmount,
- 'log.args.takerAssetFilledAmount',
- );
- expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid');
- expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid');
- expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash');
- expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData');
- expect(log.args.takerAssetData).to.be.equal(takerAssetData, 'log.args.takerAssetData');
-
- const actMakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, makerAssetData);
- expect(actMakerAssetBalanceOfMaker).to.be.bignumber.equal(
- expMakerAssetBalanceOfMaker,
- 'makerAssetBalanceOfMaker',
- );
-
- const actMakerAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync(
- makerAddress,
- makerAssetData,
- );
- expect(actMakerAssetAllowanceOfMaker).to.be.bignumber.equal(
- expMakerAssetAllowanceOfMaker,
- 'makerAssetAllowanceOfMaker',
- );
-
- const actTakerAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, takerAssetData);
- expect(actTakerAssetBalanceOfMaker).to.be.bignumber.equal(
- expTakerAssetBalanceOfMaker,
- 'takerAssetBalanceOfMaker',
- );
-
- const actZRXAssetBalanceOfMaker = await this.assetWrapper.getBalanceAsync(makerAddress, this.zrxAssetData);
- expect(actZRXAssetBalanceOfMaker).to.be.bignumber.equal(expZRXAssetBalanceOfMaker, 'ZRXAssetBalanceOfMaker');
-
- const actZRXAssetAllowanceOfMaker = await this.assetWrapper.getProxyAllowanceAsync(
- makerAddress,
- this.zrxAssetData,
- );
- expect(actZRXAssetAllowanceOfMaker).to.be.bignumber.equal(
- expZRXAssetAllowanceOfMaker,
- 'ZRXAssetAllowanceOfMaker',
- );
-
- const actTakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, takerAssetData);
- expect(actTakerAssetBalanceOfTaker).to.be.bignumber.equal(
- expTakerAssetBalanceOfTaker,
- 'TakerAssetBalanceOfTaker',
- );
-
- const actTakerAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync(
- this.takerAddress,
- takerAssetData,
- );
-
- expect(actTakerAssetAllowanceOfTaker).to.be.bignumber.equal(
- expTakerAssetAllowanceOfTaker,
- 'TakerAssetAllowanceOfTaker',
- );
-
- const actMakerAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, makerAssetData);
- expect(actMakerAssetBalanceOfTaker).to.be.bignumber.equal(
- expMakerAssetBalanceOfTaker,
- 'MakerAssetBalanceOfTaker',
- );
-
- const actZRXAssetBalanceOfTaker = await this.assetWrapper.getBalanceAsync(this.takerAddress, this.zrxAssetData);
- expect(actZRXAssetBalanceOfTaker).to.be.bignumber.equal(expZRXAssetBalanceOfTaker, 'ZRXAssetBalanceOfTaker');
-
- const actZRXAssetAllowanceOfTaker = await this.assetWrapper.getProxyAllowanceAsync(
- this.takerAddress,
- this.zrxAssetData,
- );
- expect(actZRXAssetAllowanceOfTaker).to.be.bignumber.equal(
- expZRXAssetAllowanceOfTaker,
- 'ZRXAssetAllowanceOfTaker',
- );
-
- const actZRXAssetBalanceOfFeeRecipient = await this.assetWrapper.getBalanceAsync(
- feeRecipient,
- this.zrxAssetData,
- );
- expect(actZRXAssetBalanceOfFeeRecipient).to.be.bignumber.equal(
- expZRXAssetBalanceOfFeeRecipient,
- 'ZRXAssetBalanceOfFeeRecipient',
- );
- }
- private async _abiEncodeFillOrderAndAssertOutcomeAsync(
- signedOrder: SignedOrder,
- takerAssetFillAmount: BigNumber,
- ): Promise<void> {
- const params = orderUtils.createFill(signedOrder, takerAssetFillAmount);
- const expectedAbiEncodedData = this.exchangeWrapper.abiEncodeFillOrder(signedOrder, { takerAssetFillAmount });
- const libsAbiEncodedData = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync(
- params.order,
- params.takerAssetFillAmount,
- params.signature,
- );
- expect(libsAbiEncodedData).to.be.equal(expectedAbiEncodedData, 'ABIEncodedFillOrderData');
- }
- private async _getTakerAssetFillAmountAsync(
- signedOrder: SignedOrder,
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario,
- balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher,
- orderFilledCancelledFetcher: SimpleOrderFilledCancelledFetcher,
- ): Promise<BigNumber> {
- const orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher);
- const fillableTakerAssetAmount = await orderStateUtils.getMaxFillableTakerAssetAmountAsync(
- signedOrder,
- this.takerAddress,
- );
-
- let takerAssetFillAmount;
- switch (takerAssetFillAmountScenario) {
- case TakerAssetFillAmountScenario.Zero:
- takerAssetFillAmount = new BigNumber(0);
- break;
-
- case TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount:
- takerAssetFillAmount = fillableTakerAssetAmount;
- break;
-
- case TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount:
- takerAssetFillAmount = fillableTakerAssetAmount.add(1);
- break;
-
- case TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount:
- const takerAssetProxyId = assetDataUtils.decodeAssetProxyId(signedOrder.takerAssetData);
- const makerAssetProxyId = assetDataUtils.decodeAssetProxyId(signedOrder.makerAssetData);
- const isEitherAssetERC721 =
- takerAssetProxyId === AssetProxyId.ERC721 || makerAssetProxyId === AssetProxyId.ERC721;
- if (isEitherAssetERC721) {
- throw new Error(
- 'Cannot test `TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount` together with ERC721 assets since orders involving ERC721 must always be filled exactly.',
- );
- }
- takerAssetFillAmount = fillableTakerAssetAmount.div(2).floor();
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', takerAssetFillAmountScenario);
- }
-
- return takerAssetFillAmount;
- }
- private async _modifyTraderStateAsync(
- makerStateScenario: TraderStateScenario,
- takerStateScenario: TraderStateScenario,
- signedOrder: SignedOrder,
- takerAssetFillAmount: BigNumber,
- ): Promise<void> {
- const makerAssetFillAmount = orderUtils.getPartialAmountFloor(
- takerAssetFillAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerAssetAmount,
- );
- switch (makerStateScenario.traderAssetBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (makerAssetFillAmount.eq(0)) {
- throw new Error(`Cannot set makerAssetBalanceOfMaker TooLow if makerAssetFillAmount is 0`);
- }
- const tooLowBalance = makerAssetFillAmount.minus(1);
- await this.assetWrapper.setBalanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- tooLowBalance,
- );
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = makerAssetFillAmount;
- await this.assetWrapper.setBalanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- exactBalance,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'makerStateScenario.traderAssetBalance',
- makerStateScenario.traderAssetBalance,
- );
- }
-
- const makerFee = orderUtils.getPartialAmountFloor(
- takerAssetFillAmount,
- signedOrder.takerAssetAmount,
- signedOrder.makerFee,
- );
- switch (makerStateScenario.zrxFeeBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (makerFee.eq(0)) {
- throw new Error(`Cannot set zrxAsserBalanceOfMaker TooLow if makerFee is 0`);
- }
- const tooLowBalance = makerFee.minus(1);
- await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, tooLowBalance);
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = makerFee;
- await this.assetWrapper.setBalanceAsync(signedOrder.makerAddress, this.zrxAssetData, exactBalance);
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('makerStateScenario.zrxFeeBalance', makerStateScenario.zrxFeeBalance);
- }
-
- switch (makerStateScenario.traderAssetAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = makerAssetFillAmount.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- tooLowAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = makerAssetFillAmount;
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- exactAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- signedOrder.makerAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'makerStateScenario.traderAssetAllowance',
- makerStateScenario.traderAssetAllowance,
- );
- }
-
- switch (makerStateScenario.zrxFeeAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = makerFee.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- this.zrxAssetData,
- tooLowAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = makerFee;
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- this.zrxAssetData,
- exactAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- signedOrder.makerAddress,
- this.zrxAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'makerStateScenario.zrxFeeAllowance',
- makerStateScenario.zrxFeeAllowance,
- );
- }
-
- switch (takerStateScenario.traderAssetBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (takerAssetFillAmount.eq(0)) {
- throw new Error(`Cannot set takerAssetBalanceOfTaker TooLow if takerAssetFillAmount is 0`);
- }
- const tooLowBalance = takerAssetFillAmount.minus(1);
- await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, tooLowBalance);
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = takerAssetFillAmount;
- await this.assetWrapper.setBalanceAsync(this.takerAddress, signedOrder.takerAssetData, exactBalance);
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'takerStateScenario.traderAssetBalance',
- takerStateScenario.traderAssetBalance,
- );
- }
-
- const takerFee = orderUtils.getPartialAmountFloor(
- takerAssetFillAmount,
- signedOrder.takerAssetAmount,
- signedOrder.takerFee,
- );
- switch (takerStateScenario.zrxFeeBalance) {
- case BalanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case BalanceAmountScenario.TooLow:
- if (takerFee.eq(0)) {
- throw new Error(`Cannot set zrxAssetBalanceOfTaker TooLow if takerFee is 0`);
- }
- const tooLowBalance = takerFee.minus(1);
- await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, tooLowBalance);
- break;
-
- case BalanceAmountScenario.Exact:
- const exactBalance = takerFee;
- await this.assetWrapper.setBalanceAsync(this.takerAddress, this.zrxAssetData, exactBalance);
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('takerStateScenario.zrxFeeBalance', takerStateScenario.zrxFeeBalance);
- }
-
- switch (takerStateScenario.traderAssetAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = takerAssetFillAmount.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- signedOrder.takerAssetData,
- tooLowAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = takerAssetFillAmount;
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- signedOrder.takerAssetData,
- exactAllowance,
- );
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- signedOrder.takerAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'takerStateScenario.traderAssetAllowance',
- takerStateScenario.traderAssetAllowance,
- );
- }
-
- switch (takerStateScenario.zrxFeeAllowance) {
- case AllowanceAmountScenario.Higher:
- break; // Noop since this is already the default
-
- case AllowanceAmountScenario.TooLow:
- const tooLowAllowance = takerFee.minus(1);
- await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, tooLowAllowance);
- break;
-
- case AllowanceAmountScenario.Exact:
- const exactAllowance = takerFee;
- await this.assetWrapper.setProxyAllowanceAsync(this.takerAddress, this.zrxAssetData, exactAllowance);
- break;
-
- case AllowanceAmountScenario.Unlimited:
- await this.assetWrapper.setProxyAllowanceAsync(
- this.takerAddress,
- this.zrxAssetData,
- constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- break;
-
- default:
- throw errorUtils.spawnSwitchErr(
- 'takerStateScenario.zrxFeeAllowance',
- takerStateScenario.zrxFeeAllowance,
- );
- }
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/contracts/test/utils/formatters.ts b/packages/contracts/test/utils/formatters.ts
deleted file mode 100644
index 813eb45db..000000000
--- a/packages/contracts/test/utils/formatters.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-
-import { constants } from './constants';
-import { orderUtils } from './order_utils';
-import { BatchCancelOrders, BatchFillOrders, MarketBuyOrders, MarketSellOrders } from './types';
-
-export const formatters = {
- createBatchFill(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[] = []): BatchFillOrders {
- const batchFill: BatchFillOrders = {
- orders: [],
- signatures: [],
- takerAssetFillAmounts,
- };
- _.forEach(signedOrders, signedOrder => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- batchFill.orders.push(orderWithoutExchangeAddress);
- batchFill.signatures.push(signedOrder.signature);
- if (takerAssetFillAmounts.length < signedOrders.length) {
- batchFill.takerAssetFillAmounts.push(signedOrder.takerAssetAmount);
- }
- });
- return batchFill;
- },
- createMarketSellOrders(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): MarketSellOrders {
- const marketSellOrders: MarketSellOrders = {
- orders: [],
- signatures: [],
- takerAssetFillAmount,
- };
- _.forEach(signedOrders, (signedOrder, i) => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- if (i !== 0) {
- orderWithoutExchangeAddress.takerAssetData = constants.NULL_BYTES;
- }
- marketSellOrders.orders.push(orderWithoutExchangeAddress);
- marketSellOrders.signatures.push(signedOrder.signature);
- });
- return marketSellOrders;
- },
- createMarketBuyOrders(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): MarketBuyOrders {
- const marketBuyOrders: MarketBuyOrders = {
- orders: [],
- signatures: [],
- makerAssetFillAmount,
- };
- _.forEach(signedOrders, (signedOrder, i) => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- if (i !== 0) {
- orderWithoutExchangeAddress.makerAssetData = constants.NULL_BYTES;
- }
- marketBuyOrders.orders.push(orderWithoutExchangeAddress);
- marketBuyOrders.signatures.push(signedOrder.signature);
- });
- return marketBuyOrders;
- },
- createBatchCancel(signedOrders: SignedOrder[]): BatchCancelOrders {
- const batchCancel: BatchCancelOrders = {
- orders: [],
- };
- _.forEach(signedOrders, signedOrder => {
- const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
- batchCancel.orders.push(orderWithoutExchangeAddress);
- });
- return batchCancel;
- },
-};
diff --git a/packages/contracts/test/utils/forwarder_wrapper.ts b/packages/contracts/test/utils/forwarder_wrapper.ts
deleted file mode 100644
index a0bfcfe1d..000000000
--- a/packages/contracts/test/utils/forwarder_wrapper.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { ForwarderContract } from '../../generated-wrappers/forwarder';
-
-import { constants } from './constants';
-import { formatters } from './formatters';
-import { LogDecoder } from './log_decoder';
-import { MarketSellOrders } from './types';
-
-export class ForwarderWrapper {
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _forwarderContract: ForwarderContract;
- private readonly _logDecoder: LogDecoder;
- public static getPercentageOfValue(value: BigNumber, percentage: number): BigNumber {
- const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100);
- const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR);
- return newValue;
- }
- public static getWethForFeeOrders(feeAmount: BigNumber, feeOrders: SignedOrder[]): BigNumber {
- let wethAmount = new BigNumber(0);
- let remainingFeeAmount = feeAmount;
- _.forEach(feeOrders, feeOrder => {
- const feeAvailable = feeOrder.makerAssetAmount.minus(feeOrder.takerFee);
- if (!remainingFeeAmount.isZero() && feeAvailable.gt(remainingFeeAmount)) {
- wethAmount = wethAmount.plus(
- feeOrder.takerAssetAmount
- .times(remainingFeeAmount)
- .dividedBy(feeAvailable)
- .ceil(),
- );
- remainingFeeAmount = new BigNumber(0);
- } else if (!remainingFeeAmount.isZero()) {
- wethAmount = wethAmount.plus(feeOrder.takerAssetAmount);
- remainingFeeAmount = remainingFeeAmount.minus(feeAvailable);
- }
- });
- return wethAmount;
- }
- private static _createOptimizedOrders(signedOrders: SignedOrder[]): MarketSellOrders {
- _.forEach(signedOrders, (signedOrder, index) => {
- signedOrder.takerAssetData = constants.NULL_BYTES;
- if (index > 0) {
- signedOrder.makerAssetData = constants.NULL_BYTES;
- }
- });
- const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT);
- return params;
- }
- private static _createOptimizedZrxOrders(signedOrders: SignedOrder[]): MarketSellOrders {
- _.forEach(signedOrders, signedOrder => {
- signedOrder.makerAssetData = constants.NULL_BYTES;
- signedOrder.takerAssetData = constants.NULL_BYTES;
- });
- const params = formatters.createMarketSellOrders(signedOrders, constants.ZERO_AMOUNT);
- return params;
- }
- constructor(contractInstance: ForwarderContract, provider: Provider) {
- this._forwarderContract = contractInstance;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper);
- }
- public async marketSellOrdersWithEthAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- txData: TxDataPayable,
- opts: { feePercentage?: BigNumber; feeRecipient?: string } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = ForwarderWrapper._createOptimizedOrders(orders);
- const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders);
- const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage;
- const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient;
- const txHash = await this._forwarderContract.marketSellOrdersWithEth.sendTransactionAsync(
- params.orders,
- params.signatures,
- feeParams.orders,
- feeParams.signatures,
- feePercentage,
- feeRecipient,
- txData,
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async marketBuyOrdersWithEthAsync(
- orders: SignedOrder[],
- feeOrders: SignedOrder[],
- makerAssetFillAmount: BigNumber,
- txData: TxDataPayable,
- opts: { feePercentage?: BigNumber; feeRecipient?: string } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const params = ForwarderWrapper._createOptimizedOrders(orders);
- const feeParams = ForwarderWrapper._createOptimizedZrxOrders(feeOrders);
- const feePercentage = _.isUndefined(opts.feePercentage) ? constants.ZERO_AMOUNT : opts.feePercentage;
- const feeRecipient = _.isUndefined(opts.feeRecipient) ? constants.NULL_ADDRESS : opts.feeRecipient;
- const txHash = await this._forwarderContract.marketBuyOrdersWithEth.sendTransactionAsync(
- params.orders,
- makerAssetFillAmount,
- params.signatures,
- feeParams.orders,
- feeParams.signatures,
- feePercentage,
- feeRecipient,
- txData,
- );
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async withdrawAssetAsync(
- assetData: string,
- amount: BigNumber,
- txData: TxDataPayable,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._forwarderContract.withdrawAsset.sendTransactionAsync(assetData, amount, txData);
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
-}
diff --git a/packages/contracts/test/utils/log_decoder.ts b/packages/contracts/test/utils/log_decoder.ts
deleted file mode 100644
index 05b0a9204..000000000
--- a/packages/contracts/test/utils/log_decoder.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { AbiDecoder, BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import {
- AbiDefinition,
- ContractArtifact,
- DecodedLogArgs,
- LogEntry,
- LogWithDecodedArgs,
- RawLog,
- TransactionReceiptWithDecodedLogs,
-} from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { artifacts } from '../../src/artifacts';
-
-import { constants } from './constants';
-
-export class LogDecoder {
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _abiDecoder: AbiDecoder;
- public static wrapLogBigNumbers(log: any): any {
- const argNames = _.keys(log.args);
- for (const argName of argNames) {
- const isWeb3BigNumber = _.startsWith(log.args[argName].constructor.toString(), 'function BigNumber(');
- if (isWeb3BigNumber) {
- log.args[argName] = new BigNumber(log.args[argName]);
- }
- }
- }
- constructor(web3Wrapper: Web3Wrapper) {
- this._web3Wrapper = web3Wrapper;
- const abiArrays: AbiDefinition[][] = [];
- _.forEach(artifacts, (artifact: ContractArtifact) => {
- const compilerOutput = artifact.compilerOutput;
- abiArrays.push(compilerOutput.abi);
- });
- this._abiDecoder = new AbiDecoder(abiArrays);
- }
- public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
- const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
- // tslint:disable-next-line:no-unnecessary-type-assertion
- if (_.isUndefined((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args)) {
- throw new Error(`Unable to decode log: ${JSON.stringify(log)}`);
- }
- LogDecoder.wrapLogBigNumbers(logWithDecodedArgsOrLog);
- return logWithDecodedArgsOrLog;
- }
- public async getTxWithDecodedLogsAsync(txHash: string): Promise<TransactionReceiptWithDecodedLogs> {
- const tx = await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
- tx.logs = _.map(tx.logs, log => this.decodeLogOrThrow(log));
- return tx;
- }
-}
diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts
deleted file mode 100644
index 6c2c84959..000000000
--- a/packages/contracts/test/utils/match_order_tester.ts
+++ /dev/null
@@ -1,566 +0,0 @@
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { AssetProxyId, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types';
-
-import { chaiSetup } from './chai_setup';
-import { ERC20Wrapper } from './erc20_wrapper';
-import { ERC721Wrapper } from './erc721_wrapper';
-import { ExchangeWrapper } from './exchange_wrapper';
-import {
- ERC20BalancesByOwner,
- ERC721TokenIdsByOwner,
- OrderInfo,
- OrderStatus,
- TransferAmountsByMatchOrders as TransferAmounts,
- TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts,
-} from './types';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-export class MatchOrderTester {
- private readonly _exchangeWrapper: ExchangeWrapper;
- private readonly _erc20Wrapper: ERC20Wrapper;
- private readonly _erc721Wrapper: ERC721Wrapper;
- private readonly _feeTokenAddress: string;
- /// @dev Checks values from the logs produced by Exchange.matchOrders against the expected transfer amounts.
- /// Values include the amounts transferred from the left/right makers and taker, along with
- /// the fees paid on each matched order. These are also the return values of MatchOrders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders.
- /// @param takerAddress Address of taker (account that called Exchange.matchOrders)
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- private static async _assertLogsAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- transactionReceipt: TransactionReceiptWithDecodedLogs,
- takerAddress: string,
- expectedTransferAmounts: TransferAmounts,
- ): Promise<void> {
- // Should have two fill event logs -- one for each order.
- const transactionFillLogs = _.filter(transactionReceipt.logs, ['event', 'Fill']);
- expect(transactionFillLogs.length, 'Checking number of logs').to.be.equal(2);
- // First log is for left fill
- const leftLog = (transactionFillLogs[0] as any).args as LoggedTransferAmounts;
- expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal(
- signedOrderLeft.makerAddress,
- );
- expect(leftLog.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress);
- const amountBoughtByLeftMaker = new BigNumber(leftLog.takerAssetFilledAmount);
- const amountSoldByLeftMaker = new BigNumber(leftLog.makerAssetFilledAmount);
- const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid);
- const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid);
- // Second log is for right fill
- const rightLog = (transactionFillLogs[1] as any).args as LoggedTransferAmounts;
- expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal(
- signedOrderRight.makerAddress,
- );
- expect(rightLog.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress);
- const amountBoughtByRightMaker = new BigNumber(rightLog.takerAssetFilledAmount);
- const amountSoldByRightMaker = new BigNumber(rightLog.makerAssetFilledAmount);
- const feePaidByRightMaker = new BigNumber(rightLog.makerFeePaid);
- const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid);
- // Derive amount received by taker
- const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker);
- // Assert log values - left order
- expect(amountBoughtByLeftMaker, 'Checking logged amount bought by left maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByLeftMaker,
- );
- expect(amountSoldByLeftMaker, 'Checking logged amount sold by left maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountSoldByLeftMaker,
- );
- expect(feePaidByLeftMaker, 'Checking logged fee paid by left maker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByLeftMaker,
- );
- expect(feePaidByTakerLeft, 'Checking logged fee paid on left order by taker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByTakerLeft,
- );
- // Assert log values - right order
- expect(amountBoughtByRightMaker, 'Checking logged amount bought by right maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- expect(amountSoldByRightMaker, 'Checking logged amount sold by right maker').to.be.bignumber.equal(
- expectedTransferAmounts.amountSoldByRightMaker,
- );
- expect(feePaidByRightMaker, 'Checking logged fee paid by right maker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByRightMaker,
- );
- expect(feePaidByTakerRight, 'Checking logged fee paid on right order by taker').to.be.bignumber.equal(
- expectedTransferAmounts.feePaidByTakerRight,
- );
- // Assert derived amount received by taker
- expect(amountReceivedByTaker, 'Checking logged amount received by taker').to.be.bignumber.equal(
- expectedTransferAmounts.amountReceivedByTaker,
- );
- }
- /// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings.
- /// @param expectedERC20BalancesByOwner Expected ERC20 balances.
- /// @param realERC20BalancesByOwner Real ERC20 balances.
- /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
- /// @param realERC721TokenIdsByOwner Real ERC20 token owners.
- private static async _assertAllKnownBalancesAsync(
- expectedERC20BalancesByOwner: ERC20BalancesByOwner,
- realERC20BalancesByOwner: ERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- ): Promise<void> {
- // ERC20 Balances
- const areERC20BalancesEqual = _.isEqual(expectedERC20BalancesByOwner, realERC20BalancesByOwner);
- expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true();
- // ERC721 Token Ids
- const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(expectedERC721TokenIdsByOwner, tokenIdsByOwner => {
- _.mapValues(tokenIdsByOwner, tokenIds => {
- _.sortBy(tokenIds);
- });
- });
- const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => {
- _.mapValues(tokenIdsByOwner, tokenIds => {
- _.sortBy(tokenIds);
- });
- });
- const areERC721TokenIdsEqual = _.isEqual(
- sortedExpectedNewERC721TokenIdsByOwner,
- sortedNewERC721TokenIdsByOwner,
- );
- expect(areERC721TokenIdsEqual, 'Checking all known ERC721 account balances').to.be.true();
- }
- /// @dev Constructs new MatchOrderTester.
- /// @param exchangeWrapper Used to call to the Exchange.
- /// @param erc20Wrapper Used to fetch ERC20 balances.
- /// @param erc721Wrapper Used to fetch ERC721 token owners.
- /// @param feeTokenAddress Address of ERC20 fee token.
- constructor(
- exchangeWrapper: ExchangeWrapper,
- erc20Wrapper: ERC20Wrapper,
- erc721Wrapper: ERC721Wrapper,
- feeTokenAddress: string,
- ) {
- this._exchangeWrapper = exchangeWrapper;
- this._erc20Wrapper = erc20Wrapper;
- this._erc721Wrapper = erc721Wrapper;
- this._feeTokenAddress = feeTokenAddress;
- }
- /// @dev Matches two complementary orders and asserts results.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param takerAddress Address of taker (the address who matched the two orders)
- /// @param erc20BalancesByOwner Current ERC20 balances.
- /// @param erc721TokenIdsByOwner Current ERC721 token owners.
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
- /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
- /// @return New ERC20 balances & ERC721 token owners.
- public async matchOrdersAndAssertEffectsAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- takerAddress: string,
- erc20BalancesByOwner: ERC20BalancesByOwner,
- erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
- expectedTransferAmounts: TransferAmounts,
- initialLeftOrderFilledAmount: BigNumber = new BigNumber(0),
- initialRightOrderFilledAmount: BigNumber = new BigNumber(0),
- ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> {
- // Assert initial order states
- await this._assertInitialOrderStatesAsync(
- signedOrderLeft,
- signedOrderRight,
- initialLeftOrderFilledAmount,
- initialRightOrderFilledAmount,
- );
- // Match left & right orders
- const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- );
- const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
- const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
- // Assert logs
- await MatchOrderTester._assertLogsAsync(
- signedOrderLeft,
- signedOrderRight,
- transactionReceipt,
- takerAddress,
- expectedTransferAmounts,
- );
- // Assert exchange state
- await this._assertExchangeStateAsync(
- signedOrderLeft,
- signedOrderRight,
- initialLeftOrderFilledAmount,
- initialRightOrderFilledAmount,
- expectedTransferAmounts,
- );
- // Assert balances of makers, taker, and fee recipients
- await this._assertBalancesAsync(
- signedOrderLeft,
- signedOrderRight,
- erc20BalancesByOwner,
- erc721TokenIdsByOwner,
- newERC20BalancesByOwner,
- newERC721TokenIdsByOwner,
- expectedTransferAmounts,
- takerAddress,
- );
- return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
- }
- /// @dev Asserts initial exchange state for the left and right orders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders.
- /// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders.
- private async _assertInitialOrderStatesAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- expectedOrderFilledAmountLeft: BigNumber,
- expectedOrderFilledAmountRight: BigNumber,
- ): Promise<void> {
- // Assert left order initial state
- const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderLeft),
- );
- expect(orderTakerAssetFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal(
- expectedOrderFilledAmountLeft,
- );
- // Assert right order initial state
- const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderRight),
- );
- expect(orderTakerAssetFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal(
- expectedOrderFilledAmountRight,
- );
- }
- /// @dev Asserts the exchange state against the expected amounts transferred by from matching orders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
- /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
- /// @return TransferAmounts A struct containing the expected transfer amounts.
- private async _assertExchangeStateAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- initialLeftOrderFilledAmount: BigNumber,
- initialRightOrderFilledAmount: BigNumber,
- expectedTransferAmounts: TransferAmounts,
- ): Promise<void> {
- // Assert state for left order: amount bought by left maker
- let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderLeft),
- );
- amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount);
- expect(amountBoughtByLeftMaker, 'Checking exchange state for left order').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByLeftMaker,
- );
- // Assert state for right order: amount bought by right maker
- let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
- orderHashUtils.getOrderHashHex(signedOrderRight),
- );
- amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount);
- expect(amountBoughtByRightMaker, 'Checking exchange state for right order').to.be.bignumber.equal(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- // Assert left order status
- const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount);
- const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
- const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker)
- ? OrderStatus.FULLY_FILLED
- : OrderStatus.FILLABLE;
- expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal(
- leftExpectedStatus,
- );
- // Assert right order status
- const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount);
- const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight);
- const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker)
- ? OrderStatus.FULLY_FILLED
- : OrderStatus.FILLABLE;
- expect(rightOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for right order').to.be.equal(
- rightExpectedStatus,
- );
- }
- /// @dev Asserts account balances after matching orders.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param initialERC20BalancesByOwner ERC20 balances prior to order matching.
- /// @param initialERC721TokenIdsByOwner ERC721 token owners prior to order matching.
- /// @param finalERC20BalancesByOwner ERC20 balances after order matching.
- /// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching.
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- /// @param takerAddress Address of taker (account that called Exchange.matchOrders).
- private async _assertBalancesAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- initialERC20BalancesByOwner: ERC20BalancesByOwner,
- initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- finalERC20BalancesByOwner: ERC20BalancesByOwner,
- finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- expectedTransferAmounts: TransferAmounts,
- takerAddress: string,
- ): Promise<void> {
- let expectedERC20BalancesByOwner: ERC20BalancesByOwner;
- let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
- [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances(
- signedOrderLeft,
- signedOrderRight,
- takerAddress,
- initialERC20BalancesByOwner,
- initialERC721TokenIdsByOwner,
- expectedTransferAmounts,
- );
- // Assert balances of makers, taker, and fee recipients
- await this._assertMakerTakerAndFeeRecipientBalancesAsync(
- signedOrderLeft,
- signedOrderRight,
- expectedERC20BalancesByOwner,
- finalERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner,
- finalERC721TokenIdsByOwner,
- takerAddress,
- );
- // Assert balances for all known accounts
- await MatchOrderTester._assertAllKnownBalancesAsync(
- expectedERC20BalancesByOwner,
- finalERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner,
- finalERC721TokenIdsByOwner,
- );
- }
- /// @dev Calculates the expected balances of order makers, fee recipients, and the taker,
- /// as a result of matching two orders.
- /// @param signedOrderRight First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param takerAddress Address of taker (the address who matched the two orders)
- /// @param erc20BalancesByOwner Current ERC20 balances.
- /// @param erc721TokenIdsByOwner Current ERC721 token owners.
- /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
- /// @return Expected ERC20 balances & ERC721 token owners after orders have been matched.
- private _calculateExpectedBalances(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- takerAddress: string,
- erc20BalancesByOwner: ERC20BalancesByOwner,
- erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
- expectedTransferAmounts: TransferAmounts,
- ): [ERC20BalancesByOwner, ERC721TokenIdsByOwner] {
- const makerAddressLeft = signedOrderLeft.makerAddress;
- const makerAddressRight = signedOrderRight.makerAddress;
- const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress;
- const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
- // Operations are performed on copies of the balances
- const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner);
- const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner);
- // Left Maker Asset (Right Taker Asset)
- const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData);
- if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
- // Decode asset data
- const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = erc20AssetData.tokenAddress;
- const takerAssetAddressRight = makerAssetAddressLeft;
- // Left Maker
- expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- makerAddressLeft
- ][makerAssetAddressLeft].minus(expectedTransferAmounts.amountSoldByLeftMaker);
- // Right Maker
- expectedNewERC20BalancesByOwner[makerAddressRight][
- takerAssetAddressRight
- ] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add(
- expectedTransferAmounts.amountBoughtByRightMaker,
- );
- // Taker
- expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- takerAddress
- ][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker);
- } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
- // Decode asset data
- const erc721AssetData = assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = erc721AssetData.tokenAddress;
- const makerAssetIdLeft = erc721AssetData.tokenId;
- const takerAssetAddressRight = makerAssetAddressLeft;
- const takerAssetIdRight = makerAssetIdLeft;
- // Left Maker
- _.remove(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft], makerAssetIdLeft);
- // Right Maker
- expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight].push(takerAssetIdRight);
- // Taker: Since there is only 1 asset transferred, the taker does not receive any of the left maker asset.
- }
- // Left Taker Asset (Right Maker Asset)
- // Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset.
- const takerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.takerAssetData);
- if (takerAssetProxyIdLeft === AssetProxyId.ERC20) {
- // Decode asset data
- const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.takerAssetData);
- const takerAssetAddressLeft = erc20AssetData.tokenAddress;
- const makerAssetAddressRight = takerAssetAddressLeft;
- // Left Maker
- expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
- makerAddressLeft
- ][takerAssetAddressLeft].add(expectedTransferAmounts.amountBoughtByLeftMaker);
- // Right Maker
- expectedNewERC20BalancesByOwner[makerAddressRight][
- makerAssetAddressRight
- ] = expectedNewERC20BalancesByOwner[makerAddressRight][makerAssetAddressRight].minus(
- expectedTransferAmounts.amountSoldByRightMaker,
- );
- } else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) {
- // Decode asset data
- const erc721AssetData = assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
- const makerAssetAddressRight = erc721AssetData.tokenAddress;
- const makerAssetIdRight = erc721AssetData.tokenId;
- const takerAssetAddressLeft = makerAssetAddressRight;
- const takerAssetIdLeft = makerAssetIdRight;
- // Right Maker
- _.remove(expectedNewERC721TokenIdsByOwner[makerAddressRight][makerAssetAddressRight], makerAssetIdRight);
- // Left Maker
- expectedNewERC721TokenIdsByOwner[makerAddressLeft][takerAssetAddressLeft].push(takerAssetIdLeft);
- }
- // Left Maker Fees
- expectedNewERC20BalancesByOwner[makerAddressLeft][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
- makerAddressLeft
- ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByLeftMaker);
- // Right Maker Fees
- expectedNewERC20BalancesByOwner[makerAddressRight][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
- makerAddressRight
- ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByRightMaker);
- // Taker Fees
- expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
- takerAddress
- ][this._feeTokenAddress].minus(
- expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight),
- );
- // Left Fee Recipient Fees
- expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][
- this._feeTokenAddress
- ] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].add(
- expectedTransferAmounts.feePaidByLeftMaker.add(expectedTransferAmounts.feePaidByTakerLeft),
- );
- // Right Fee Recipient Fees
- expectedNewERC20BalancesByOwner[feeRecipientAddressRight][
- this._feeTokenAddress
- ] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].add(
- expectedTransferAmounts.feePaidByRightMaker.add(expectedTransferAmounts.feePaidByTakerRight),
- );
-
- return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner];
- }
- /// @dev Asserts ERC20 account balances and ERC721 token holdings that result from order matching.
- /// Specifically checks balances of makers, taker and fee recipients.
- /// @param signedOrderLeft First matched order.
- /// @param signedOrderRight Second matched order.
- /// @param expectedERC20BalancesByOwner Expected ERC20 balances.
- /// @param realERC20BalancesByOwner Real ERC20 balances.
- /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
- /// @param realERC721TokenIdsByOwner Real ERC20 token owners.
- /// @param takerAddress Address of taker (account that called Exchange.matchOrders).
- private async _assertMakerTakerAndFeeRecipientBalancesAsync(
- signedOrderLeft: SignedOrder,
- signedOrderRight: SignedOrder,
- expectedERC20BalancesByOwner: ERC20BalancesByOwner,
- realERC20BalancesByOwner: ERC20BalancesByOwner,
- expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
- takerAddress: string,
- ): Promise<void> {
- // Individual balance comparisons
- const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData);
- const makerERC20AssetDataLeft =
- makerAssetProxyIdLeft === AssetProxyId.ERC20
- ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData)
- : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress;
- const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData);
- const makerERC20AssetDataRight =
- makerAssetProxyIdRight === AssetProxyId.ERC20
- ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData)
- : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
- const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress;
- if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
- expect(
- realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft],
- 'Checking left maker egress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]);
- expect(
- realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft],
- 'Checking right maker ingress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]);
- expect(
- realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft],
- 'Checking taker ingress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]);
- } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
- expect(
- realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
- 'Checking left maker egress ERC721 account holdings',
- ).to.be.deep.equal(
- expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
- );
- expect(
- realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
- 'Checking right maker ERC721 account holdings',
- ).to.be.deep.equal(
- expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
- );
- expect(
- realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(),
- 'Checking taker ingress ERC721 account holdings',
- ).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort());
- } else {
- throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`);
- }
- if (makerAssetProxyIdRight === AssetProxyId.ERC20) {
- expect(
- realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight],
- 'Checking left maker ingress ERC20 account balance',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]);
- expect(
- realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
- 'Checking right maker egress ERC20 account balance',
- ).to.be.bignumber.equal(
- expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
- );
- } else if (makerAssetProxyIdRight === AssetProxyId.ERC721) {
- expect(
- realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
- 'Checking left maker ingress ERC721 account holdings',
- ).to.be.deep.equal(
- expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
- );
- expect(
- realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
- 'Checking right maker agress ERC721 account holdings',
- ).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]);
- } else {
- throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`);
- }
- // Paid fees
- expect(
- realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress],
- 'Checking left maker egress ERC20 account fees',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]);
- expect(
- realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress],
- 'Checking right maker egress ERC20 account fees',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]);
- expect(
- realERC20BalancesByOwner[takerAddress][this._feeTokenAddress],
- 'Checking taker egress ERC20 account fees',
- ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]);
- // Received fees
- expect(
- realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
- 'Checking left fee recipient ingress ERC20 account fees',
- ).to.be.bignumber.equal(
- expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
- );
- expect(
- realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
- 'Checking right fee receipient ingress ERC20 account fees',
- ).to.be.bignumber.equal(
- expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
- );
- }
-} // tslint:disable-line:max-file-line-count
diff --git a/packages/contracts/test/utils/multi_sig_wrapper.ts b/packages/contracts/test/utils/multi_sig_wrapper.ts
deleted file mode 100644
index 74fd3b4d6..000000000
--- a/packages/contracts/test/utils/multi_sig_wrapper.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { AssetProxyOwnerContract } from '../../generated-wrappers/asset_proxy_owner';
-import { MultiSigWalletContract } from '../../generated-wrappers/multi_sig_wallet';
-
-import { LogDecoder } from './log_decoder';
-
-export class MultiSigWrapper {
- private readonly _multiSig: MultiSigWalletContract;
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _logDecoder: LogDecoder;
- constructor(multiSigContract: MultiSigWalletContract, provider: Provider) {
- this._multiSig = multiSigContract;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._logDecoder = new LogDecoder(this._web3Wrapper);
- }
- public async submitTransactionAsync(
- destination: string,
- data: string,
- from: string,
- opts: { value?: BigNumber } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const value = _.isUndefined(opts.value) ? new BigNumber(0) : opts.value;
- const txHash = await this._multiSig.submitTransaction.sendTransactionAsync(destination, value, data, {
- from,
- });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async confirmTransactionAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._multiSig.confirmTransaction.sendTransactionAsync(txId, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async revokeConfirmationAsync(txId: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._multiSig.revokeConfirmation.sendTransactionAsync(txId, { from });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async executeTransactionAsync(
- txId: BigNumber,
- from: string,
- opts: { gas?: number } = {},
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const txHash = await this._multiSig.executeTransaction.sendTransactionAsync(txId, {
- from,
- gas: opts.gas,
- });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
- public async executeRemoveAuthorizedAddressAtIndexAsync(
- txId: BigNumber,
- from: string,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- // tslint:disable-next-line:no-unnecessary-type-assertion
- const txHash = await (this
- ._multiSig as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync(txId, {
- from,
- });
- const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
- return tx;
- }
-}
diff --git a/packages/contracts/test/utils/order_factory.ts b/packages/contracts/test/utils/order_factory.ts
deleted file mode 100644
index 2449d1a8a..000000000
--- a/packages/contracts/test/utils/order_factory.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils';
-import { Order, SignatureType, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-import { getLatestBlockTimestampAsync } from './block_timestamp';
-import { constants } from './constants';
-import { signingUtils } from './signing_utils';
-
-export class OrderFactory {
- private readonly _defaultOrderParams: Partial<Order>;
- private readonly _privateKey: Buffer;
- constructor(privateKey: Buffer, defaultOrderParams: Partial<Order>) {
- this._defaultOrderParams = defaultOrderParams;
- this._privateKey = privateKey;
- }
- public async newSignedOrderAsync(
- customOrderParams: Partial<Order> = {},
- signatureType: SignatureType = SignatureType.EthSign,
- ): Promise<SignedOrder> {
- const tenMinutesInSeconds = 10 * 60;
- const currentBlockTimestamp = await getLatestBlockTimestampAsync();
- const order = ({
- senderAddress: constants.NULL_ADDRESS,
- expirationTimeSeconds: new BigNumber(currentBlockTimestamp).add(tenMinutesInSeconds),
- salt: generatePseudoRandomSalt(),
- takerAddress: constants.NULL_ADDRESS,
- ...this._defaultOrderParams,
- ...customOrderParams,
- } as any) as Order;
- const orderHashBuff = orderHashUtils.getOrderHashBuffer(order);
- const signature = signingUtils.signMessage(orderHashBuff, this._privateKey, signatureType);
- const signedOrder = {
- ...order,
- signature: `0x${signature.toString('hex')}`,
- };
- return signedOrder;
- }
-}
diff --git a/packages/contracts/test/utils/order_factory_from_scenario.ts b/packages/contracts/test/utils/order_factory_from_scenario.ts
deleted file mode 100644
index 60c8606c4..000000000
--- a/packages/contracts/test/utils/order_factory_from_scenario.ts
+++ /dev/null
@@ -1,296 +0,0 @@
-import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { Order } from '@0x/types';
-import { BigNumber, errorUtils } from '@0x/utils';
-
-import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
-
-import { constants } from './constants';
-import {
- AssetDataScenario,
- ERC721TokenIdsByOwner,
- ExpirationTimeSecondsScenario,
- FeeRecipientAddressScenario,
- OrderAssetAmountScenario,
- OrderScenario,
- TakerScenario,
-} from './types';
-
-const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber(10_000_000_000_000_000_000);
-const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(5_000_000_000_000_000_000);
-const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100_000_000_000_000_000);
-const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50_000_000_000_000_000);
-const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1_000_000);
-const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500_000);
-const TEN_UNITS_ZERO_DECIMALS = new BigNumber(10);
-const ONE_THOUSAND_UNITS_ZERO_DECIMALS = new BigNumber(1000);
-const ONE_NFT_UNIT = new BigNumber(1);
-
-export class OrderFactoryFromScenario {
- private readonly _userAddresses: string[];
- private readonly _zrxAddress: string;
- private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[];
- private readonly _erc20FiveDecimalTokenAddresses: string[];
- private readonly _erc20ZeroDecimalTokenAddresses: string[];
- private readonly _erc721Token: DummyERC721TokenContract;
- private readonly _erc721Balances: ERC721TokenIdsByOwner;
- private readonly _exchangeAddress: string;
- constructor(
- userAddresses: string[],
- zrxAddress: string,
- nonZrxERC20EighteenDecimalTokenAddresses: string[],
- erc20FiveDecimalTokenAddresses: string[],
- erc20ZeroDecimalTokenAddresses: string[],
- erc721Token: DummyERC721TokenContract,
- erc721Balances: ERC721TokenIdsByOwner,
- exchangeAddress: string,
- ) {
- this._userAddresses = userAddresses;
- this._zrxAddress = zrxAddress;
- this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses;
- this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses;
- this._erc20ZeroDecimalTokenAddresses = erc20ZeroDecimalTokenAddresses;
- this._erc721Token = erc721Token;
- this._erc721Balances = erc721Balances;
- this._exchangeAddress = exchangeAddress;
- }
- public generateOrder(orderScenario: OrderScenario): Order {
- const makerAddress = this._userAddresses[1];
- let takerAddress = this._userAddresses[2];
- const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721Token.address];
- const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721Token.address];
- let feeRecipientAddress;
- let makerAssetAmount;
- let takerAssetAmount;
- let makerFee;
- let takerFee;
- let expirationTimeSeconds;
- let makerAssetData;
- let takerAssetData;
-
- switch (orderScenario.feeRecipientScenario) {
- case FeeRecipientAddressScenario.BurnAddress:
- feeRecipientAddress = constants.NULL_ADDRESS;
- break;
- case FeeRecipientAddressScenario.EthUserAddress:
- feeRecipientAddress = this._userAddresses[4];
- break;
- default:
- throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', orderScenario.feeRecipientScenario);
- }
-
- switch (orderScenario.makerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._zrxAddress);
- break;
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._nonZrxERC20EighteenDecimalTokenAddresses[0]);
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]);
- break;
- case AssetDataScenario.ERC721:
- makerAssetData = assetDataUtils.encodeERC721AssetData(
- this._erc721Token.address,
- erc721MakerAssetIds[0],
- );
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]);
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
- }
-
- switch (orderScenario.takerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._zrxAddress);
- break;
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._nonZrxERC20EighteenDecimalTokenAddresses[1]);
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]);
- break;
- case AssetDataScenario.ERC721:
- takerAssetData = assetDataUtils.encodeERC721AssetData(
- this._erc721Token.address,
- erc721TakerAssetIds[0],
- );
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]);
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
- }
-
- switch (orderScenario.makerAssetAmountScenario) {
- case OrderAssetAmountScenario.Large:
- switch (orderScenario.makerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- makerAssetAmount = TEN_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- makerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Small:
- switch (orderScenario.makerAssetDataScenario) {
- case AssetDataScenario.ZRXFeeToken:
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- makerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- makerAssetAmount = FIVE_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- makerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- makerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Zero:
- makerAssetAmount = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerAssetAmountScenario);
- }
-
- switch (orderScenario.takerAssetAmountScenario) {
- case OrderAssetAmountScenario.Large:
- switch (orderScenario.takerAssetDataScenario) {
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- case AssetDataScenario.ZRXFeeToken:
- takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- takerAssetAmount = TEN_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- takerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Small:
- switch (orderScenario.takerAssetDataScenario) {
- case AssetDataScenario.ERC20NonZRXEighteenDecimals:
- case AssetDataScenario.ZRXFeeToken:
- takerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case AssetDataScenario.ERC20FiveDecimals:
- takerAssetAmount = FIVE_UNITS_FIVE_DECIMALS;
- break;
- case AssetDataScenario.ERC721:
- takerAssetAmount = ONE_NFT_UNIT;
- break;
- case AssetDataScenario.ERC20ZeroDecimals:
- takerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
- break;
- default:
- throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
- }
- break;
- case OrderAssetAmountScenario.Zero:
- takerAssetAmount = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerAssetAmountScenario);
- }
-
- switch (orderScenario.makerFeeScenario) {
- case OrderAssetAmountScenario.Large:
- makerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Small:
- makerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Zero:
- makerFee = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.makerFeeScenario);
- }
-
- switch (orderScenario.takerFeeScenario) {
- case OrderAssetAmountScenario.Large:
- takerFee = POINT_ONE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Small:
- takerFee = POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS;
- break;
- case OrderAssetAmountScenario.Zero:
- takerFee = new BigNumber(0);
- break;
- default:
- throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', orderScenario.takerFeeScenario);
- }
-
- switch (orderScenario.expirationTimeSecondsScenario) {
- case ExpirationTimeSecondsScenario.InFuture:
- expirationTimeSeconds = new BigNumber(2524604400); // Close to infinite
- break;
- case ExpirationTimeSecondsScenario.InPast:
- expirationTimeSeconds = new BigNumber(0); // Jan 1, 1970
- break;
- default:
- throw errorUtils.spawnSwitchErr(
- 'ExpirationTimeSecondsScenario',
- orderScenario.expirationTimeSecondsScenario,
- );
- }
-
- switch (orderScenario.takerScenario) {
- case TakerScenario.CorrectlySpecified:
- break; // noop since takerAddress is already specified
-
- case TakerScenario.IncorrectlySpecified:
- const notTaker = this._userAddresses[3];
- takerAddress = notTaker;
- break;
-
- case TakerScenario.Unspecified:
- takerAddress = constants.NULL_ADDRESS;
- break;
-
- default:
- throw errorUtils.spawnSwitchErr('TakerScenario', orderScenario.takerScenario);
- }
-
- const order = {
- senderAddress: constants.NULL_ADDRESS,
- makerAddress,
- takerAddress,
- makerFee,
- takerFee,
- makerAssetAmount,
- takerAssetAmount,
- makerAssetData,
- takerAssetData,
- salt: generatePseudoRandomSalt(),
- exchangeAddress: this._exchangeAddress,
- feeRecipientAddress,
- expirationTimeSeconds,
- };
-
- return order;
- }
-}
diff --git a/packages/contracts/test/utils/order_utils.ts b/packages/contracts/test/utils/order_utils.ts
deleted file mode 100644
index 4f7a34011..000000000
--- a/packages/contracts/test/utils/order_utils.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { OrderWithoutExchangeAddress, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-import { constants } from './constants';
-import { CancelOrder, MatchOrder } from './types';
-
-export const orderUtils = {
- getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
- const partialAmount = numerator
- .mul(target)
- .div(denominator)
- .floor();
- return partialAmount;
- },
- createFill: (signedOrder: SignedOrder, takerAssetFillAmount?: BigNumber) => {
- const fill = {
- order: orderUtils.getOrderWithoutExchangeAddress(signedOrder),
- takerAssetFillAmount: takerAssetFillAmount || signedOrder.takerAssetAmount,
- signature: signedOrder.signature,
- };
- return fill;
- },
- createCancel(signedOrder: SignedOrder, takerAssetCancelAmount?: BigNumber): CancelOrder {
- const cancel = {
- order: orderUtils.getOrderWithoutExchangeAddress(signedOrder),
- takerAssetCancelAmount: takerAssetCancelAmount || signedOrder.takerAssetAmount,
- };
- return cancel;
- },
- getOrderWithoutExchangeAddress(signedOrder: SignedOrder): OrderWithoutExchangeAddress {
- const orderStruct = {
- senderAddress: signedOrder.senderAddress,
- makerAddress: signedOrder.makerAddress,
- takerAddress: signedOrder.takerAddress,
- feeRecipientAddress: signedOrder.feeRecipientAddress,
- makerAssetAmount: signedOrder.makerAssetAmount,
- takerAssetAmount: signedOrder.takerAssetAmount,
- makerFee: signedOrder.makerFee,
- takerFee: signedOrder.takerFee,
- expirationTimeSeconds: signedOrder.expirationTimeSeconds,
- salt: signedOrder.salt,
- makerAssetData: signedOrder.makerAssetData,
- takerAssetData: signedOrder.takerAssetData,
- };
- return orderStruct;
- },
- createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder): MatchOrder {
- const fill = {
- left: orderUtils.getOrderWithoutExchangeAddress(signedOrderLeft),
- right: orderUtils.getOrderWithoutExchangeAddress(signedOrderRight),
- leftSignature: signedOrderLeft.signature,
- rightSignature: signedOrderRight.signature,
- };
- fill.right.makerAssetData = constants.NULL_BYTES;
- fill.right.takerAssetData = constants.NULL_BYTES;
- return fill;
- },
-};
diff --git a/packages/contracts/test/utils/profiler.ts b/packages/contracts/test/utils/profiler.ts
deleted file mode 100644
index 2c7c1d66c..000000000
--- a/packages/contracts/test/utils/profiler.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { devConstants } from '@0x/dev-utils';
-import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov';
-import * as _ from 'lodash';
-
-let profilerSubprovider: ProfilerSubprovider;
-
-export const profiler = {
- start(): void {
- profiler.getProfilerSubproviderSingleton().start();
- },
- stop(): void {
- profiler.getProfilerSubproviderSingleton().stop();
- },
- getProfilerSubproviderSingleton(): ProfilerSubprovider {
- if (_.isUndefined(profilerSubprovider)) {
- profilerSubprovider = profiler._getProfilerSubprovider();
- }
- return profilerSubprovider;
- },
- _getProfilerSubprovider(): ProfilerSubprovider {
- const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
- const isVerbose = true;
- const subprovider = new ProfilerSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
- return subprovider;
- },
-};
diff --git a/packages/contracts/test/utils/revert_trace.ts b/packages/contracts/test/utils/revert_trace.ts
deleted file mode 100644
index 3f74fd28b..000000000
--- a/packages/contracts/test/utils/revert_trace.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { devConstants } from '@0x/dev-utils';
-import { RevertTraceSubprovider, SolCompilerArtifactAdapter } from '@0x/sol-cov';
-import * as _ from 'lodash';
-
-let revertTraceSubprovider: RevertTraceSubprovider;
-
-export const revertTrace = {
- getRevertTraceSubproviderSingleton(): RevertTraceSubprovider {
- if (_.isUndefined(revertTraceSubprovider)) {
- revertTraceSubprovider = revertTrace._getRevertTraceSubprovider();
- }
- return revertTraceSubprovider;
- },
- _getRevertTraceSubprovider(): RevertTraceSubprovider {
- const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
- const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
- const isVerbose = true;
- const subprovider = new RevertTraceSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
- return subprovider;
- },
-};
diff --git a/packages/contracts/test/utils/signing_utils.ts b/packages/contracts/test/utils/signing_utils.ts
deleted file mode 100644
index 21f864bfa..000000000
--- a/packages/contracts/test/utils/signing_utils.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { SignatureType } from '@0x/types';
-import * as ethUtil from 'ethereumjs-util';
-
-export const signingUtils = {
- signMessage(message: Buffer, privateKey: Buffer, signatureType: SignatureType): Buffer {
- if (signatureType === SignatureType.EthSign) {
- const prefixedMessage = ethUtil.hashPersonalMessage(message);
- const ecSignature = ethUtil.ecsign(prefixedMessage, privateKey);
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(signatureType),
- ]);
- return signature;
- } else if (signatureType === SignatureType.EIP712) {
- const ecSignature = ethUtil.ecsign(message, privateKey);
- const signature = Buffer.concat([
- ethUtil.toBuffer(ecSignature.v),
- ecSignature.r,
- ecSignature.s,
- ethUtil.toBuffer(signatureType),
- ]);
- return signature;
- } else {
- throw new Error(`${signatureType} is not a valid signature type`);
- }
- },
-};
diff --git a/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts
deleted file mode 100644
index 64b7dedbe..000000000
--- a/packages/contracts/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { AbstractBalanceAndProxyAllowanceFetcher } from '@0x/order-utils';
-import { BigNumber } from '@0x/utils';
-
-import { AssetWrapper } from './asset_wrapper';
-
-export class SimpleAssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher {
- private readonly _assetWrapper: AssetWrapper;
- constructor(assetWrapper: AssetWrapper) {
- this._assetWrapper = assetWrapper;
- }
- public async getBalanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
- const balance = await this._assetWrapper.getBalanceAsync(userAddress, assetData);
- return balance;
- }
- public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise<BigNumber> {
- const proxyAllowance = await this._assetWrapper.getProxyAllowanceAsync(userAddress, assetData);
- return proxyAllowance;
- }
-}
diff --git a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts b/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
deleted file mode 100644
index af959e00e..000000000
--- a/packages/contracts/test/utils/simple_order_filled_cancelled_fetcher.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils';
-import { SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-
-import { ExchangeWrapper } from './exchange_wrapper';
-
-export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher {
- private readonly _exchangeWrapper: ExchangeWrapper;
- private readonly _zrxAssetData: string;
- constructor(exchange: ExchangeWrapper, zrxAssetData: string) {
- this._exchangeWrapper = exchange;
- this._zrxAssetData = zrxAssetData;
- }
- public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
- const filledTakerAmount = new BigNumber(await this._exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash));
- return filledTakerAmount;
- }
- public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const isCancelled = await this._exchangeWrapper.isCancelledAsync(orderHash);
- const orderEpoch = await this._exchangeWrapper.getOrderEpochAsync(
- signedOrder.makerAddress,
- signedOrder.senderAddress,
- );
- const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt;
- return isCancelled || isCancelledByOrderEpoch;
- }
- public getZRXAssetData(): string {
- return this._zrxAssetData;
- }
-}
diff --git a/packages/contracts/test/utils/test_with_reference.ts b/packages/contracts/test/utils/test_with_reference.ts
deleted file mode 100644
index b80be4a6c..000000000
--- a/packages/contracts/test/utils/test_with_reference.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import * as chai from 'chai';
-import * as _ from 'lodash';
-
-import { chaiSetup } from './chai_setup';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-class Value<T> {
- public value: T;
- constructor(value: T) {
- this.value = value;
- }
-}
-
-// tslint:disable-next-line: max-classes-per-file
-class ErrorMessage {
- public error: string;
- constructor(message: string) {
- this.error = message;
- }
-}
-
-type PromiseResult<T> = Value<T> | ErrorMessage;
-
-// TODO(albrow): This seems like a generic utility function that could exist in
-// lodash. We should replace it by a library implementation, or move it to our
-// own.
-async function evaluatePromise<T>(promise: Promise<T>): Promise<PromiseResult<T>> {
- try {
- return new Value<T>(await promise);
- } catch (e) {
- return new ErrorMessage(e.message);
- }
-}
-
-export async function testWithReferenceFuncAsync<P0, R>(
- referenceFunc: (p0: P0) => Promise<R>,
- testFunc: (p0: P0) => Promise<R>,
- values: [P0],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, R>(
- referenceFunc: (p0: P0, p1: P1) => Promise<R>,
- testFunc: (p0: P0, p1: P1) => Promise<R>,
- values: [P0, P1],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, P2, R>(
- referenceFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2) => Promise<R>,
- values: [P0, P1, P2],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, P2, P3, R>(
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3) => Promise<R>,
- values: [P0, P1, P2, P3],
-): Promise<void>;
-export async function testWithReferenceFuncAsync<P0, P1, P2, P3, P4, R>(
- referenceFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- testFunc: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => Promise<R>,
- values: [P0, P1, P2, P3, P4],
-): Promise<void>;
-
-/**
- * Tests the behavior of a test function by comparing it to the expected
- * behavior (defined by a reference function).
- *
- * First the reference function will be called to obtain an "expected result",
- * or if the reference function throws/rejects, an "expected error". Next, the
- * test function will be called to obtain an "actual result", or if the test
- * function throws/rejects, an "actual error". The test passes if at least one
- * of the following conditions is met:
- *
- * 1) Neither the reference function or the test function throw and the
- * "expected result" equals the "actual result".
- *
- * 2) Both the reference function and the test function throw and the "actual
- * error" message *contains* the "expected error" message.
- *
- * @param referenceFuncAsync a reference function implemented in pure
- * JavaScript/TypeScript which accepts N arguments and returns the "expected
- * result" or throws/rejects with the "expected error".
- * @param testFuncAsync a test function which, e.g., makes a call or sends a
- * transaction to a contract. It accepts the same N arguments returns the
- * "actual result" or throws/rejects with the "actual error".
- * @param values an array of N values, where each value corresponds in-order to
- * an argument to both the test function and the reference function.
- * @return A Promise that resolves if the test passes and rejects if the test
- * fails, according to the rules described above.
- */
-export async function testWithReferenceFuncAsync(
- referenceFuncAsync: (...args: any[]) => Promise<any>,
- testFuncAsync: (...args: any[]) => Promise<any>,
- values: any[],
-): Promise<void> {
- // Measure correct behaviour
- const expected = await evaluatePromise(referenceFuncAsync(...values));
-
- // Measure actual behaviour
- const actual = await evaluatePromise(testFuncAsync(...values));
-
- // Compare behaviour
- if (expected instanceof ErrorMessage) {
- // If we expected an error, check if the actual error message contains the
- // expected error message.
- if (!(actual instanceof ErrorMessage)) {
- throw new Error(
- `Expected error containing ${expected.error} but got no error\n\tTest case: ${_getTestCaseString(
- referenceFuncAsync,
- values,
- )}`,
- );
- }
- expect(actual.error).to.contain(
- expected.error,
- `${actual.error}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`,
- );
- } else {
- // If we do not expect an error, compare actual and expected directly.
- expect(actual).to.deep.equal(expected, `Test case ${_getTestCaseString(referenceFuncAsync, values)}`);
- }
-}
-
-function _getTestCaseString(referenceFuncAsync: (...args: any[]) => Promise<any>, values: any[]): string {
- const paramNames = _getParameterNames(referenceFuncAsync);
- return JSON.stringify(_.zipObject(paramNames, values));
-}
-
-// Source: https://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically
-function _getParameterNames(func: (...args: any[]) => any): string[] {
- return _.toString(func)
- .replace(/[/][/].*$/gm, '') // strip single-line comments
- .replace(/\s+/g, '') // strip white space
- .replace(/[/][*][^/*]*[*][/]/g, '') // strip multi-line comments
- .split('){', 1)[0]
- .replace(/^[^(]*[(]/, '') // extract the parameters
- .replace(/=[^,]+/g, '') // strip any ES6 defaults
- .split(',')
- .filter(Boolean); // split & filter [""]
-}
diff --git a/packages/contracts/test/utils/transaction_factory.ts b/packages/contracts/test/utils/transaction_factory.ts
deleted file mode 100644
index dbab3ade4..000000000
--- a/packages/contracts/test/utils/transaction_factory.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { eip712Utils, generatePseudoRandomSalt } from '@0x/order-utils';
-import { SignatureType } from '@0x/types';
-import { signTypedDataUtils } from '@0x/utils';
-import * as ethUtil from 'ethereumjs-util';
-
-import { signingUtils } from './signing_utils';
-import { SignedTransaction } from './types';
-
-export class TransactionFactory {
- private readonly _signerBuff: Buffer;
- private readonly _exchangeAddress: string;
- private readonly _privateKey: Buffer;
- constructor(privateKey: Buffer, exchangeAddress: string) {
- this._privateKey = privateKey;
- this._exchangeAddress = exchangeAddress;
- this._signerBuff = ethUtil.privateToAddress(this._privateKey);
- }
- public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction {
- const salt = generatePseudoRandomSalt();
- const signerAddress = `0x${this._signerBuff.toString('hex')}`;
- const executeTransactionData = {
- salt,
- signerAddress,
- data,
- };
-
- const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, this._exchangeAddress);
- const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
- const signature = signingUtils.signMessage(eip712MessageBuffer, this._privateKey, signatureType);
- const signedTx = {
- exchangeAddress: this._exchangeAddress,
- signature: `0x${signature.toString('hex')}`,
- ...executeTransactionData,
- };
- return signedTx;
- }
-}
diff --git a/packages/contracts/test/utils/type_encoding_utils.ts b/packages/contracts/test/utils/type_encoding_utils.ts
deleted file mode 100644
index bfd9c9ef5..000000000
--- a/packages/contracts/test/utils/type_encoding_utils.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import BN = require('bn.js');
-import ethUtil = require('ethereumjs-util');
-
-import { constants } from './constants';
-
-export const typeEncodingUtils = {
- encodeUint256(value: BigNumber): Buffer {
- const base = 10;
- const formattedValue = new BN(value.toString(base));
- const encodedValue = ethUtil.toBuffer(formattedValue);
- // tslint:disable-next-line:custom-no-magic-numbers
- const paddedValue = ethUtil.setLengthLeft(encodedValue, constants.WORD_LENGTH);
- return paddedValue;
- },
- decodeUint256(encodedValue: Buffer): BigNumber {
- const formattedValue = ethUtil.bufferToHex(encodedValue);
- const value = new BigNumber(formattedValue, constants.BASE_16);
- return value;
- },
-};
diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts
deleted file mode 100644
index 9fc9e1570..000000000
--- a/packages/contracts/test/utils/types.ts
+++ /dev/null
@@ -1,241 +0,0 @@
-import { OrderWithoutExchangeAddress } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { AbiDefinition } from 'ethereum-types';
-
-export interface ERC20BalancesByOwner {
- [ownerAddress: string]: {
- [tokenAddress: string]: BigNumber;
- };
-}
-
-export interface ERC721TokenIdsByOwner {
- [ownerAddress: string]: {
- [tokenAddress: string]: BigNumber[];
- };
-}
-
-export interface SubmissionContractEventArgs {
- transactionId: BigNumber;
-}
-
-export interface BatchFillOrders {
- orders: OrderWithoutExchangeAddress[];
- signatures: string[];
- takerAssetFillAmounts: BigNumber[];
-}
-
-export interface MarketSellOrders {
- orders: OrderWithoutExchangeAddress[];
- signatures: string[];
- takerAssetFillAmount: BigNumber;
-}
-
-export interface MarketBuyOrders {
- orders: OrderWithoutExchangeAddress[];
- signatures: string[];
- makerAssetFillAmount: BigNumber;
-}
-
-export interface BatchCancelOrders {
- orders: OrderWithoutExchangeAddress[];
-}
-
-export interface CancelOrdersBefore {
- salt: BigNumber;
-}
-
-export interface TransactionDataParams {
- name: string;
- abi: AbiDefinition[];
- args: any[];
-}
-
-export interface MultiSigConfig {
- owners: string[];
- confirmationsRequired: number;
- secondsRequired: number;
-}
-
-export interface MultiSigConfigByNetwork {
- [networkName: string]: MultiSigConfig;
-}
-
-export interface Token {
- address?: string;
- name: string;
- symbol: string;
- decimals: number;
- ipfsHash: string;
- swarmHash: string;
-}
-
-export enum OrderStatus {
- INVALID,
- INVALID_MAKER_ASSET_AMOUNT,
- INVALID_TAKER_ASSET_AMOUNT,
- FILLABLE,
- EXPIRED,
- FULLY_FILLED,
- CANCELLED,
-}
-
-export enum ContractName {
- TokenRegistry = 'TokenRegistry',
- MultiSigWalletWithTimeLock = 'MultiSigWalletWithTimeLock',
- Exchange = 'Exchange',
- ZRXToken = 'ZRXToken',
- DummyERC20Token = 'DummyERC20Token',
- EtherToken = 'WETH9',
- AssetProxyOwner = 'AssetProxyOwner',
- AccountLevels = 'AccountLevels',
- EtherDelta = 'EtherDelta',
- Arbitrage = 'Arbitrage',
- TestAssetDataDecoders = 'TestAssetDataDecoders',
- TestAssetProxyDispatcher = 'TestAssetProxyDispatcher',
- TestLibs = 'TestLibs',
- TestSignatureValidator = 'TestSignatureValidator',
- ERC20Proxy = 'ERC20Proxy',
- ERC721Proxy = 'ERC721Proxy',
- DummyERC721Receiver = 'DummyERC721Receiver',
- DummyERC721Token = 'DummyERC721Token',
- TestLibBytes = 'TestLibBytes',
- TestWallet = 'TestWallet',
- Authorizable = 'Authorizable',
- Whitelist = 'Whitelist',
- Forwarder = 'Forwarder',
-}
-
-export interface SignedTransaction {
- exchangeAddress: string;
- salt: BigNumber;
- signerAddress: string;
- data: string;
- signature: string;
-}
-
-export interface TransferAmountsByMatchOrders {
- // Left Maker
- amountBoughtByLeftMaker: BigNumber;
- amountSoldByLeftMaker: BigNumber;
- feePaidByLeftMaker: BigNumber;
- // Right Maker
- amountBoughtByRightMaker: BigNumber;
- amountSoldByRightMaker: BigNumber;
- feePaidByRightMaker: BigNumber;
- // Taker
- amountReceivedByTaker: BigNumber;
- feePaidByTakerLeft: BigNumber;
- feePaidByTakerRight: BigNumber;
-}
-
-export interface TransferAmountsLoggedByMatchOrders {
- makerAddress: string;
- takerAddress: string;
- makerAssetFilledAmount: string;
- takerAssetFilledAmount: string;
- makerFeePaid: string;
- takerFeePaid: string;
-}
-
-export interface OrderInfo {
- orderStatus: number;
- orderHash: string;
- orderTakerAssetFilledAmount: BigNumber;
-}
-
-export interface CancelOrder {
- order: OrderWithoutExchangeAddress;
- takerAssetCancelAmount: BigNumber;
-}
-
-export interface MatchOrder {
- left: OrderWithoutExchangeAddress;
- right: OrderWithoutExchangeAddress;
- leftSignature: string;
- rightSignature: string;
-}
-
-// Combinatorial testing types
-
-export enum FeeRecipientAddressScenario {
- BurnAddress = 'BURN_ADDRESS',
- EthUserAddress = 'ETH_USER_ADDRESS',
-}
-
-export enum OrderAssetAmountScenario {
- Zero = 'ZERO',
- Large = 'LARGE',
- Small = 'SMALL',
-}
-
-export enum TakerScenario {
- CorrectlySpecified = 'CORRECTLY_SPECIFIED',
- IncorrectlySpecified = 'INCORRECTLY_SPECIFIED',
- Unspecified = 'UNSPECIFIED',
-}
-
-export enum ExpirationTimeSecondsScenario {
- InPast = 'IN_PAST',
- InFuture = 'IN_FUTURE',
-}
-
-export enum AssetDataScenario {
- ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS',
- ZRXFeeToken = 'ZRX_FEE_TOKEN',
- ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS',
- ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS',
- ERC721 = 'ERC721',
-}
-
-export enum TakerAssetFillAmountScenario {
- Zero = 'ZERO',
- GreaterThanRemainingFillableTakerAssetAmount = 'GREATER_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT',
- LessThanRemainingFillableTakerAssetAmount = 'LESS_THAN_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT',
- ExactlyRemainingFillableTakerAssetAmount = 'EXACTLY_REMAINING_FILLABLE_TAKER_ASSET_AMOUNT',
-}
-
-export interface OrderScenario {
- takerScenario: TakerScenario;
- feeRecipientScenario: FeeRecipientAddressScenario;
- makerAssetAmountScenario: OrderAssetAmountScenario;
- takerAssetAmountScenario: OrderAssetAmountScenario;
- makerFeeScenario: OrderAssetAmountScenario;
- takerFeeScenario: OrderAssetAmountScenario;
- expirationTimeSecondsScenario: ExpirationTimeSecondsScenario;
- makerAssetDataScenario: AssetDataScenario;
- takerAssetDataScenario: AssetDataScenario;
-}
-
-export enum BalanceAmountScenario {
- Exact = 'EXACT',
- TooLow = 'TOO_LOW',
- Higher = 'HIGHER',
-}
-
-export enum AllowanceAmountScenario {
- Exact = 'EXACT',
- TooLow = 'TOO_LOW',
- Higher = 'HIGHER',
- Unlimited = 'UNLIMITED',
-}
-
-export interface TraderStateScenario {
- traderAssetBalance: BalanceAmountScenario;
- traderAssetAllowance: AllowanceAmountScenario;
- zrxFeeBalance: BalanceAmountScenario;
- zrxFeeAllowance: AllowanceAmountScenario;
-}
-
-export interface FillScenario {
- orderScenario: OrderScenario;
- takerAssetFillAmountScenario: TakerAssetFillAmountScenario;
- makerStateScenario: TraderStateScenario;
- takerStateScenario: TraderStateScenario;
-}
-
-export interface FillResults {
- makerAssetFilledAmount: BigNumber;
- takerAssetFilledAmount: BigNumber;
- makerFeePaid: BigNumber;
- takerFeePaid: BigNumber;
-}
diff --git a/packages/contracts/test/utils/web3_wrapper.ts b/packages/contracts/test/utils/web3_wrapper.ts
deleted file mode 100644
index f7b1a732a..000000000
--- a/packages/contracts/test/utils/web3_wrapper.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { devConstants, env, EnvVars, web3Factory } from '@0x/dev-utils';
-import { prependSubprovider, Web3ProviderEngine } from '@0x/subproviders';
-import { logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as _ from 'lodash';
-
-import { coverage } from './coverage';
-import { profiler } from './profiler';
-import { revertTrace } from './revert_trace';
-
-enum ProviderType {
- Ganache = 'ganache',
- Geth = 'geth',
-}
-
-let testProvider: ProviderType;
-switch (process.env.TEST_PROVIDER) {
- case undefined:
- testProvider = ProviderType.Ganache;
- break;
- case 'ganache':
- testProvider = ProviderType.Ganache;
- break;
- case 'geth':
- testProvider = ProviderType.Geth;
- break;
- default:
- throw new Error(`Unknown TEST_PROVIDER: ${process.env.TEST_PROVIDER}`);
-}
-
-const ganacheTxDefaults = {
- from: devConstants.TESTRPC_FIRST_ADDRESS,
- gas: devConstants.GAS_LIMIT,
-};
-const gethTxDefaults = {
- from: devConstants.TESTRPC_FIRST_ADDRESS,
-};
-export const txDefaults = testProvider === ProviderType.Ganache ? ganacheTxDefaults : gethTxDefaults;
-
-const gethConfigs = {
- shouldUseInProcessGanache: false,
- rpcUrl: 'http://localhost:8501',
- shouldUseFakeGasEstimate: false,
-};
-const ganacheConfigs = {
- shouldUseInProcessGanache: true,
-};
-const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs;
-
-export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs);
-const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
-const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler);
-const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace);
-const enabledSubproviderCount = _.filter(
- [isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled],
- _.identity.bind(_),
-).length;
-if (enabledSubproviderCount > 1) {
- throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`);
-}
-if (isCoverageEnabled) {
- const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
- prependSubprovider(provider, coverageSubprovider);
-}
-if (isProfilerEnabled) {
- if (testProvider === ProviderType.Ganache) {
- logUtils.warn(
- "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth",
- );
- process.exit(1);
- }
- const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
- logUtils.log(
- "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
- );
- profilerSubprovider.stop();
- prependSubprovider(provider, profilerSubprovider);
-}
-if (isRevertTraceEnabled) {
- const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton();
- prependSubprovider(provider, revertTraceSubprovider);
-}
-
-export const web3Wrapper = new Web3Wrapper(provider);
diff --git a/packages/contracts/test/utils_test/test_with_reference.ts b/packages/contracts/test/utils_test/test_with_reference.ts
deleted file mode 100644
index 8d633cd1f..000000000
--- a/packages/contracts/test/utils_test/test_with_reference.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as chai from 'chai';
-
-import { chaiSetup } from '../utils/chai_setup';
-import { testWithReferenceFuncAsync } from '../utils/test_with_reference';
-
-chaiSetup.configure();
-const expect = chai.expect;
-
-async function divAsync(x: number, y: number): Promise<number> {
- if (y === 0) {
- throw new Error('MathError: divide by zero');
- }
- return x / y;
-}
-
-// returns an async function that always returns the given value.
-function alwaysValueFunc(value: number): (x: number, y: number) => Promise<number> {
- return async (x: number, y: number) => value;
-}
-
-// returns an async function which always throws/rejects with the given error
-// message.
-function alwaysFailFunc(errMessage: string): (x: number, y: number) => Promise<number> {
- return async (x: number, y: number) => {
- throw new Error(errMessage);
- };
-}
-
-describe('testWithReferenceFuncAsync', () => {
- it('passes when both succeed and actual === expected', async () => {
- await testWithReferenceFuncAsync(alwaysValueFunc(0.5), divAsync, [1, 2]);
- });
-
- it('passes when both fail and actual error contains expected error', async () => {
- await testWithReferenceFuncAsync(alwaysFailFunc('divide by zero'), divAsync, [1, 0]);
- });
-
- it('fails when both succeed and actual !== expected', async () => {
- expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2])).to.be.rejectedWith(
- 'Test case {"x":1,"y":2}: expected { value: 0.5 } to deeply equal { value: 3 }',
- );
- });
-
- it('fails when both fail and actual error does not contain expected error', async () => {
- expect(
- testWithReferenceFuncAsync(alwaysFailFunc('Unexpected math error'), divAsync, [1, 0]),
- ).to.be.rejectedWith(
- 'MathError: divide by zero\n\tTest case: {"x":1,"y":0}: expected \'MathError: divide by zero\' to include \'Unexpected math error\'',
- );
- });
-
- it('fails when referenceFunc succeeds and testFunc fails', async () => {
- expect(testWithReferenceFuncAsync(alwaysValueFunc(0), divAsync, [1, 0])).to.be.rejectedWith(
- 'Test case {"x":1,"y":0}: expected { error: \'MathError: divide by zero\' } to deeply equal { value: 0 }',
- );
- });
-
- it('fails when referenceFunc fails and testFunc succeeds', async () => {
- expect(testWithReferenceFuncAsync(alwaysFailFunc('divide by zero'), divAsync, [1, 2])).to.be.rejectedWith(
- 'Expected error containing divide by zero but got no error\n\tTest case: {"x":1,"y":2}',
- );
- });
-});
diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json
deleted file mode 100644
index 8b29365cc..000000000
--- a/packages/contracts/tsconfig.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "extends": "../../tsconfig",
- "compilerOptions": {
- "outDir": "lib",
- "rootDir": ".",
- "resolveJsonModule": true
- },
- "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
- "files": [
- "./generated-artifacts/AssetProxyOwner.json",
- "./generated-artifacts/DummyERC20Token.json",
- "./generated-artifacts/DummyERC721Receiver.json",
- "./generated-artifacts/DummyERC721Token.json",
- "./generated-artifacts/DummyMultipleReturnERC20Token.json",
- "./generated-artifacts/DummyNoReturnERC20Token.json",
- "./generated-artifacts/ERC20Proxy.json",
- "./generated-artifacts/ERC20Token.json",
- "./generated-artifacts/ERC721Proxy.json",
- "./generated-artifacts/ERC721Token.json",
- "./generated-artifacts/Exchange.json",
- "./generated-artifacts/ExchangeWrapper.json",
- "./generated-artifacts/Forwarder.json",
- "./generated-artifacts/IAssetData.json",
- "./generated-artifacts/IAssetProxy.json",
- "./generated-artifacts/IValidator.json",
- "./generated-artifacts/IWallet.json",
- "./generated-artifacts/InvalidERC721Receiver.json",
- "./generated-artifacts/MixinAuthorizable.json",
- "./generated-artifacts/MultiSigWallet.json",
- "./generated-artifacts/MultiSigWalletWithTimeLock.json",
- "./generated-artifacts/OrderValidator.json",
- "./generated-artifacts/ReentrantERC20Token.json",
- "./generated-artifacts/TestAssetProxyDispatcher.json",
- "./generated-artifacts/TestAssetProxyOwner.json",
- "./generated-artifacts/TestConstants.json",
- "./generated-artifacts/TestExchangeInternals.json",
- "./generated-artifacts/TestLibBytes.json",
- "./generated-artifacts/TestLibs.json",
- "./generated-artifacts/TestSignatureValidator.json",
- "./generated-artifacts/TestStaticCallReceiver.json",
- "./generated-artifacts/Validator.json",
- "./generated-artifacts/WETH9.json",
- "./generated-artifacts/Wallet.json",
- "./generated-artifacts/Whitelist.json",
- "./generated-artifacts/ZRXToken.json"
- ],
- "exclude": ["./deploy/solc/solc_bin"]
-}
diff --git a/packages/contracts/tslint.json b/packages/contracts/tslint.json
deleted file mode 100644
index 1bb3ac2a2..000000000
--- a/packages/contracts/tslint.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": ["@0x/tslint-config"],
- "rules": {
- "custom-no-magic-numbers": false
- }
-}
diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json
index eb320c103..4b13beb01 100644
--- a/packages/dev-tools-pages/package.json
+++ b/packages/dev-tools-pages/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/dev-tools-pages",
- "version": "0.0.7",
+ "version": "0.0.8",
"engines": {
"node": ">=6.12"
},
@@ -16,7 +16,7 @@
},
"license": "Apache-2.0",
"dependencies": {
- "@0x/react-shared": "^1.0.22",
+ "@0x/react-shared": "^1.0.23",
"basscss": "^8.0.3",
"bowser": "^1.9.3",
"less": "^2.7.2",
diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json
index 4f47f0f45..417a3c65e 100644
--- a/packages/dev-utils/CHANGELOG.json
+++ b/packages/dev-utils/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "1.0.19",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.0.18",
"changes": [
diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md
index 3ab8192c7..1842c6824 100644
--- a/packages/dev-utils/CHANGELOG.md
+++ b/packages/dev-utils/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.19 - _November 28, 2018_
+
+ * Dependencies updated
+
## v1.0.18 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/dev-utils/README.md b/packages/dev-utils/README.md
index 73b0b8816..b85159dd8 100644
--- a/packages/dev-utils/README.md
+++ b/packages/dev-utils/README.md
@@ -27,6 +27,21 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
}
```
+## Troubleshooting
+
+If you are still seeing TS type errors complaining about missing DOM types such as `Response`:
+
+```
+error TS2304: Cannot find name 'Response'.
+```
+
+Then you need to explicitly add the `dom` lib to your compiler options in `tsconfig.json`. The `dom` library is included by default, but customizing the `lib` option can cause it to be dropped.
+
+```
+"compilerOptions": {
+ "lib": [..., "dom"],
+```
+
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json
index e7cd62a81..a3b5c9090 100644
--- a/packages/dev-utils/package.json
+++ b/packages/dev-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/dev-utils",
- "version": "1.0.18",
+ "version": "1.0.19",
"engines": {
"node": ">=6.12"
},
@@ -41,11 +41,11 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/subproviders": "^2.1.5",
+ "@0x/subproviders": "^2.1.6",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@types/web3-provider-engine": "^14.0.0",
"chai": "^4.0.1",
"ethereum-types": "^1.1.2",
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/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json
index f83a6612d..58ba49509 100644
--- a/packages/fill-scenarios/CHANGELOG.json
+++ b/packages/fill-scenarios/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "1.0.14",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.0.13",
"changes": [
diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md
index 3c39e1650..aa7df302e 100644
--- a/packages/fill-scenarios/CHANGELOG.md
+++ b/packages/fill-scenarios/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.14 - _November 28, 2018_
+
+ * Dependencies updated
+
## v1.0.13 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json
index e91ed8a4e..b29eb674c 100644
--- a/packages/fill-scenarios/package.json
+++ b/packages/fill-scenarios/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/fill-scenarios",
- "version": "1.0.13",
+ "version": "1.0.14",
"description": "0x order fill scenario generator",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@@ -28,14 +28,14 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.1.0",
- "@0x/base-contract": "^3.0.7",
- "@0x/contract-artifacts": "^1.1.0",
- "@0x/order-utils": "^3.0.3",
+ "@0x/abi-gen-wrappers": "^2.0.0",
+ "@0x/base-contract": "^3.0.8",
+ "@0x/contract-artifacts": "^1.1.2",
+ "@0x/order-utils": "^3.0.4",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
"lodash": "^4.17.5"
diff --git a/packages/instant/.DS_Store b/packages/instant/.DS_Store
new file mode 100644
index 000000000..9a0cceca6
--- /dev/null
+++ b/packages/instant/.DS_Store
Binary files differ
diff --git a/packages/instant/.dogfood.discharge.json b/packages/instant/.dogfood.discharge.json
index ca36b3861..651b3daa6 100644
--- a/packages/instant/.dogfood.discharge.json
+++ b/packages/instant/.dogfood.discharge.json
@@ -1,12 +1,12 @@
{
"domain": "0x-instant-dogfood",
- "build_command": "WEBPACK_OUTPUT_PATH=public yarn build:umd:prod",
+ "build_command": "WEBPACK_OUTPUT_PATH=public dotenv yarn build -- --env.discharge_target=dogfood",
"upload_directory": "public",
"index_key": "index.html",
"error_key": "index.html",
"trailing_slashes": true,
"cache": 3600,
- "aws_profile": "default",
+ "aws_profile": "0xproject",
"aws_region": "us-east-1",
"cdn": false,
"dns_configured": true
diff --git a/packages/instant/.env_example b/packages/instant/.env_example
new file mode 100644
index 000000000..234e64bbe
--- /dev/null
+++ b/packages/instant/.env_example
@@ -0,0 +1,7 @@
+INSTANT_ROLLBAR_PUBLISH_TOKEN=
+INSTANT_ROLLBAR_CLIENT_TOKEN=
+INSTANT_HEAP_ANALYTICS_ID_PRODUCTION=
+INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT=
+# if you want to report to heap or rollbar when building in development mode, you can use the following:
+# INSTANT_HEAP_FORCE_DEVELOPMENT=true
+# INSTANT_ROLLBAR_FORCE_DEVELOPMENT=true \ No newline at end of file
diff --git a/packages/instant/.gitignore b/packages/instant/.gitignore
index a99cea187..2e65f192d 100644
--- a/packages/instant/.gitignore
+++ b/packages/instant/.gitignore
@@ -1,3 +1,4 @@
public/instant.js
public/instant.js.map
-umd/* \ No newline at end of file
+umd/*
+.env \ No newline at end of file
diff --git a/packages/instant/.npmignore b/packages/instant/.npmignore
index a4f7810c0..563923652 100644
--- a/packages/instant/.npmignore
+++ b/packages/instant/.npmignore
@@ -2,4 +2,5 @@
*
*/
!lib/**/*
-!umd/**/* \ No newline at end of file
+!umd/**/*
+.env \ No newline at end of file
diff --git a/packages/instant/.production.discharge.json b/packages/instant/.production.discharge.json
new file mode 100644
index 000000000..1ce39fdd8
--- /dev/null
+++ b/packages/instant/.production.discharge.json
@@ -0,0 +1,13 @@
+{
+ "domain": "instant.0xproject.com",
+ "build_command": "dotenv yarn build -- --env.discharge_target=production",
+ "upload_directory": "umd",
+ "index_key": "instant.js",
+ "error_key": "404.html",
+ "trailing_slashes": true,
+ "cache": 3600,
+ "aws_profile": "0xproject",
+ "aws_region": "us-east-1",
+ "cdn": true,
+ "dns_configured": true
+}
diff --git a/packages/instant/.staging.discharge.json b/packages/instant/.staging.discharge.json
index c917a650b..844e3ca4e 100644
--- a/packages/instant/.staging.discharge.json
+++ b/packages/instant/.staging.discharge.json
@@ -1,12 +1,12 @@
{
"domain": "0x-instant-staging",
- "build_command": "WEBPACK_OUTPUT_PATH=public yarn build:umd:prod",
+ "build_command": "WEBPACK_OUTPUT_PATH=public dotenv yarn build -- --env.discharge_target=staging",
"upload_directory": "public",
"index_key": "index.html",
"error_key": "index.html",
"trailing_slashes": true,
"cache": 3600,
- "aws_profile": "default",
+ "aws_profile": "0xproject",
"aws_region": "us-east-1",
"cdn": false,
"dns_configured": true
diff --git a/packages/instant/README.md b/packages/instant/README.md
index b83a10508..2092b45d9 100644
--- a/packages/instant/README.md
+++ b/packages/instant/README.md
@@ -2,39 +2,11 @@
## Installation
-```bash
-yarn add @0x/instant
-```
-
-**Import**
-
-**CommonJS module**
-
-```typescript
-import { ZeroExInstant } from '@0x/instant';
-```
-
-or
-
-```javascript
-var ZeroExInstant = require('@0x/instant').ZeroExInstant;
-```
-
-If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
-
-```json
-"compilerOptions": {
- "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"],
-}
-```
-
-**UMD Module**
-
-The package is also available as a UMD module named `zeroExInstant`.
+The package is available as a UMD module named `zeroExInstant` at https://instant.0xproject.com/instant.js.
```html
<head>
- <script type="text/javascript" src="[zeroExInstantUMDPath]" charset="utf-8"></script>
+ <script type="text/javascript" src="https://instant.0xproject.com/instant.js" charset="utf-8"></script>
</head>
<body>
<div id="zeroExInstantContainer"></div>
@@ -48,23 +20,33 @@ The package is also available as a UMD module named `zeroExInstant`.
## Deploying
-You can deploy a work-in-progress version of 0x Instant at http://0x-instant-dogfood.s3-website-us-east-1.amazonaws.com for easy sharing.
+To run any of the following commands you need to configure your `.env` file. There is an example `.env_example` file to show you what values are required.
+
+You can deploy a work-in-progress version of 0x Instant at http://0x-instant-dogfood.s3-website-us-east-1.amazonaws.com/instant.js for easy sharing.
-To build and deploy the site run
+To build and deploy the bundle run
```
yarn deploy_dogfood
```
-We also have a staging bucket that is to be updated less frequently can be used to share instant externally: http://0x-instant-staging.s3-website-us-east-1.amazonaws.com/
+We also have a staging bucket that is to be updated less frequently can be used to share a beta version of instant externally: http://0x-instant-staging.s3-website-us-east-1.amazonaws.com/instant.js
-To build and deploy to this bucket, run
+To build and deploy to this bundle, run
```
yarn deploy_staging
```
-**NOTE: On deploying the site, it will say the site is available at a non-existent URL. Please ignore and use the (now updated) URL above.**
+Finally, we have our live production bundle that is only meant to be updated with stable, polished releases: https://instant.0xproject.com/instant.js
+
+To build and deploy to this bundle, run
+
+```
+yarn deploy_production
+```
+
+**NOTE: On deploying the site to staging and dogfood, it will say the site is available at a non-existent URL. Please ignore and use the (now updated) URL above.**
## Contributing
diff --git a/packages/instant/package.json b/packages/instant/package.json
index 4422dc83f..7d0bf6bec 100644
--- a/packages/instant/package.json
+++ b/packages/instant/package.json
@@ -1,20 +1,15 @@
{
"name": "@0x/instant",
- "version": "1.0.1",
+ "version": "1.0.2",
"engines": {
"node": ">=6.12"
},
"private": true,
"description": "0x Instant React Component",
- "main": "lib/index.js",
- "types": "lib/index.d.ts",
+ "main": "umd/instant.js",
"scripts": {
- "build": "yarn build:all",
- "build:all": "run-p build:umd:prod build:commonjs",
- "build:umd:prod": "webpack --mode production",
- "build:commonjs": "tsc -b",
+ "build": "webpack --mode production",
"build:ci": "yarn build",
- "watch_without_deps": "tsc -w",
"dev": "webpack-dev-server --mode development",
"lint": "tslint --format stylish --project .",
"test": "jest",
@@ -24,6 +19,7 @@
"clean": "shx rm -rf lib coverage scripts",
"deploy_dogfood": "discharge deploy -c .dogfood.discharge.json",
"deploy_staging": "discharge deploy -c .staging.discharge.json",
+ "deploy_production": "discharge deploy -c .production.discharge.json",
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
},
"config": {
@@ -46,14 +42,14 @@
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
"dependencies": {
"@0x/assert": "^1.0.18",
- "@0x/asset-buyer": "^3.0.1",
+ "@0x/asset-buyer": "^3.0.2",
"@0x/json-schemas": "^2.1.2",
- "@0x/order-utils": "^3.0.3",
- "@0x/subproviders": "^2.1.5",
+ "@0x/order-utils": "^3.0.4",
+ "@0x/subproviders": "^2.1.6",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"bowser": "^1.9.4",
"copy-to-clipboard": "^3.0.8",
"ethereum-types": "^1.1.2",
@@ -64,6 +60,7 @@
"react-redux": "^5.0.7",
"redux": "^4.0.0",
"redux-devtools-extension": "^2.13.5",
+ "rollbar": "^2.5.0",
"styled-components": "^4.0.2",
"ts-optchain": "^0.1.1"
},
@@ -81,6 +78,7 @@
"@types/redux": "^3.6.0",
"@types/styled-components": "^4.0.1",
"awesome-typescript-loader": "^5.2.1",
+ "dotenv-cli": "^1.4.0",
"enzyme": "^3.6.0",
"enzyme-adapter-react-16": "^1.5.0",
"ip": "^1.1.5",
@@ -88,7 +86,9 @@
"make-promises-safe": "^1.1.0",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
+ "rollbar-sourcemap-webpack-plugin": "^2.4.0",
"shx": "^0.2.2",
+ "source-map-loader": "^0.2.4",
"svg-react-loader": "^0.4.6",
"ts-jest": "^23.10.3",
"tslint": "5.11.0",
@@ -99,6 +99,6 @@
"webpack-dev-server": "^3.1.9"
},
"publishConfig": {
- "access": "public"
+ "access": "private"
}
}
diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html
index df39994ef..d10618c58 100644
--- a/packages/instant/public/index.html
+++ b/packages/instant/public/index.html
@@ -175,6 +175,7 @@
defaultSelectedAssetData: queryParams.getQueryParamValue('defaultSelectedAssetData'),
affiliateInfo: affiliateInfoOverride,
shouldDisablePushToHistory: !!queryParams.getQueryParamValue('shouldDisablePushToHistory'),
+ walletDisplayName: queryParams.getQueryParamValue('walletDisplayName') || undefined,
};
return renderOptionsOverrides;
};
diff --git a/packages/instant/src/assets/icons/zrx.svg b/packages/instant/src/assets/icons/zrx.svg
index 07518f551..da623710b 100644
--- a/packages/instant/src/assets/icons/zrx.svg
+++ b/packages/instant/src/assets/icons/zrx.svg
@@ -1,3 +1,6 @@
-<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M22.6726 18.5002L22.6787 18.5063L22.625 18.5868C22.641 18.558 22.6569 18.5291 22.6726 18.5002V18.5002H22.6726ZM22.7893 18.5002L21.3866 17.0053L17.9692 12.9131L19.6779 11.0919L17.1249 7.89955L18.8337 6.07835L20.0599 4.74999C20.663 5.26419 21.2058 5.83552 21.6882 6.46394C22.1707 7.09242 22.5828 7.77444 22.9245 8.5101C23.2663 9.2457 23.5309 10.0206 23.7186 10.8347C23.9062 11.6489 24 12.4916 24 13.3628C24 14.3055 23.8928 15.216 23.6784 16.0945C23.4703 16.9468 23.174 17.7487 22.7893 18.5L22.7893 18.5002ZM6.74427 15.3604L8.87512 18.1019L7.20654 19.8795L5.94009 21.2502L5.91999 21.2288C5.3169 20.7291 4.77415 20.1651 4.29169 19.5368C3.80923 18.9086 3.39714 18.2268 3.05539 17.4915C2.71365 16.7562 2.45567 15.9816 2.28144 15.1677C2.09382 14.3539 2 13.5114 2 12.6405C2 11.6981 2.10721 10.7913 2.32164 9.92041C2.53608 9.04943 2.83091 8.24276 3.20615 7.50025L4.61334 8.99943L8.45293 13.54L6.7442 15.3605L6.74427 15.3604ZM7.89849 8.87512L6.12088 7.20654L4.75015 5.94009L4.77157 5.91999C5.27132 5.3169 5.83531 4.77415 6.46352 4.29169C7.09178 3.80923 7.77357 3.39714 8.50886 3.05539C9.2442 2.71365 10.0188 2.45567 10.8326 2.28144C11.6465 2.09382 12.489 2 13.3599 2C14.3023 2 15.209 2.10721 16.08 2.32164C16.9509 2.53608 17.7576 2.83091 18.5001 3.20615L17.0866 4.55302L12.9101 8.0307L11.0896 6.32197L7.89835 8.87496L7.89849 8.87512ZM18.1019 17.1252L19.8795 18.7938L21.2503 20.0602L21.2288 20.0803C20.7291 20.6834 20.1651 21.2262 19.5369 21.7086C18.9086 22.1911 18.2268 22.6032 17.4916 22.9449C16.7562 23.2867 15.9817 23.5447 15.1678 23.7189C14.3539 23.9065 13.5114 24.0003 12.6405 24.0003C11.6981 24.0003 10.7914 23.8931 9.92046 23.6787C9.04952 23.4643 8.2428 23.1694 7.50029 22.7942L8.91381 21.4473L13.54 17.5474L15.3606 19.6782L18.1021 17.1252L18.1019 17.1252Z" fill="white"/>
+<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.62099 13.9044L6.3287 12.1375L4.20565 9.27256L1.50251 5.44771C0.547534 7.07749 0 8.97462 0 11C0 14.3552 1.50251 17.3593 3.8722 19.3768L7.30341 16.9518C6.13632 16.2248 5.19614 15.1662 4.62099 13.9044Z" fill="white"/>
+<path d="M8.09561 4.62099L9.86251 6.3287L12.7274 4.20565L16.5523 1.50251C14.9225 0.547534 13.0254 0 11 0C7.64475 0 4.64072 1.50251 2.62323 3.8722L5.04816 7.30341C5.77525 6.13632 6.83381 5.19614 8.09561 4.62099Z" fill="white"/>
+<path d="M15.6713 9.86251L17.7943 12.7274L20.4975 16.5523C21.4525 14.9225 22 13.0254 22 11C22 7.64475 20.4975 4.64072 18.1278 2.62323L14.6966 5.04816C15.8637 5.77525 16.8039 6.83381 17.379 8.09561L15.6713 9.86251Z" fill="white"/>
+<path d="M19.3768 18.1278L16.9518 14.6966C16.2248 15.8637 15.1662 16.8039 13.9044 17.379L12.1375 15.6713L9.27256 17.7943L5.44771 20.4975C7.07749 21.4525 8.97462 22 11 22C14.3552 22 17.3593 20.4975 19.3768 18.1278Z" fill="white"/>
</svg>
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 8b6121e43..1489b94d4 100644
--- a/packages/instant/src/components/buy_button.tsx
+++ b/packages/instant/src/components/buy_button.tsx
@@ -1,4 +1,5 @@
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
@@ -7,7 +8,8 @@ import { oc } from 'ts-optchain';
import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
import { ColorOption } from '../style/theme';
-import { AffiliateInfo, ZeroExInstantError } from '../types';
+import { AffiliateInfo, Asset, ZeroExInstantError } from '../types';
+import { analytics } from '../util/analytics';
import { gasPriceEstimator } from '../util/gas_price_estimator';
import { util } from '../util/util';
@@ -20,6 +22,7 @@ export interface BuyButtonProps {
assetBuyer: AssetBuyer;
web3Wrapper: Web3Wrapper;
affiliateInfo?: AffiliateInfo;
+ selectedAsset?: Asset;
onValidationPending: (buyQuote: BuyQuote) => void;
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
onSignatureDenied: (buyQuote: BuyQuote) => void;
@@ -35,8 +38,12 @@ export class BuyButton extends React.Component<BuyButtonProps> {
onBuyFailure: util.boundNoop,
};
public render(): React.ReactNode {
- const { buyQuote, accountAddress } = this.props;
+ const { buyQuote, accountAddress, selectedAsset } = this.props;
const shouldDisableButton = _.isUndefined(buyQuote) || _.isUndefined(accountAddress);
+ const buttonText =
+ !_.isUndefined(selectedAsset) && selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
+ ? `Buy ${selectedAsset.metaData.symbol.toUpperCase()}`
+ : 'Buy Now';
return (
<Button
width="100%"
@@ -44,7 +51,7 @@ export class BuyButton extends React.Component<BuyButtonProps> {
isDisabled={shouldDisableButton}
fontColor={ColorOption.white}
>
- Buy
+ {buttonText}
</Button>
);
}
@@ -59,6 +66,7 @@ export class BuyButton extends React.Component<BuyButtonProps> {
// if we don't have a balance for the user, let the transaction through, it will be handled by the wallet
const hasSufficientEth = _.isUndefined(accountEthBalanceInWei) || accountEthBalanceInWei.gte(ethNeededForBuy);
if (!hasSufficientEth) {
+ analytics.trackBuyNotEnoughEth(buyQuote);
this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH);
return;
}
@@ -66,6 +74,7 @@ export class BuyButton extends React.Component<BuyButtonProps> {
const gasInfo = await gasPriceEstimator.getGasInfoAsync();
const feeRecipient = oc(affiliateInfo).feeRecipient();
try {
+ analytics.trackBuyStarted(buyQuote);
txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, {
feeRecipient,
takerAddress: accountAddress,
@@ -74,9 +83,11 @@ export class BuyButton extends React.Component<BuyButtonProps> {
} catch (e) {
if (e instanceof Error) {
if (e.message === AssetBuyerError.SignatureRequestDenied) {
+ analytics.trackBuySignatureDenied(buyQuote);
this.props.onSignatureDenied(buyQuote);
return;
} else if (e.message === AssetBuyerError.TransactionValueTooLow) {
+ analytics.trackBuySimulationFailed(buyQuote);
this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow);
return;
}
@@ -87,14 +98,17 @@ export class BuyButton extends React.Component<BuyButtonProps> {
const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs;
this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
try {
+ analytics.trackBuyTxSubmitted(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
} catch (e) {
if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) {
+ analytics.trackBuyTxFailed(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
this.props.onBuyFailure(buyQuote, txHash);
return;
}
throw e;
}
+ analytics.trackBuyTxSucceeded(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
this.props.onBuySuccess(buyQuote, txHash);
};
}
diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx
index 6568de91b..a19f5a4d0 100644
--- a/packages/instant/src/components/buy_order_progress.tsx
+++ b/packages/instant/src/components/buy_order_progress.tsx
@@ -21,7 +21,7 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> =
const hasEnded = buyOrderState.processState !== OrderProcessState.Processing;
const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix;
return (
- <Container padding="20px 20px 0px 20px" width="100%">
+ <Container width="100%" padding="20px 20px 0px 20px">
<Container marginBottom="5px">
<TimeCounter estimatedTimeMs={expectedTimeMs} hasEnded={hasEnded} key={progress.startTimeUnix} />
</Container>
diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx
index e563bec73..833818900 100644
--- a/packages/instant/src/components/buy_order_state_buttons.tsx
+++ b/packages/instant/src/components/buy_order_state_buttons.tsx
@@ -4,7 +4,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper';
import * as React from 'react';
import { ColorOption } from '../style/theme';
-import { AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
+import { AffiliateInfo, Asset, OrderProcessState, ZeroExInstantError } from '../types';
import { BuyButton } from './buy_button';
import { PlacingOrderButton } from './placing_order_button';
@@ -21,6 +21,7 @@ export interface BuyOrderStateButtonProps {
assetBuyer: AssetBuyer;
web3Wrapper: Web3Wrapper;
affiliateInfo?: AffiliateInfo;
+ selectedAsset?: Asset;
onViewTransaction: () => void;
onValidationPending: (buyQuote: BuyQuote) => void;
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
@@ -60,6 +61,7 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
assetBuyer={props.assetBuyer}
web3Wrapper={props.web3Wrapper}
affiliateInfo={props.affiliateInfo}
+ selectedAsset={props.selectedAsset}
onValidationPending={props.onValidationPending}
onValidationFail={props.onValidationFail}
onSignatureDenied={props.onSignatureDenied}
diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx
index ff900842a..4da82eb73 100644
--- a/packages/instant/src/components/erc20_asset_amount_input.tsx
+++ b/packages/instant/src/components/erc20_asset_amount_input.tsx
@@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
);
};
private readonly _renderChevronIcon = (): React.ReactNode => {
- if (!this._areMultipleAssetsAvailable()) {
+ if (!this._areAnyAssetsAvailable()) {
return null;
}
return (
@@ -134,14 +134,14 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
// We don't want to allow opening the token selection panel if there are no assets.
// Since styles are inferred from the presence of a click handler, we want to return undefined
// instead of providing a noop.
- if (!this._areMultipleAssetsAvailable() || _.isUndefined(this.props.onSelectAssetClick)) {
+ if (!this._areAnyAssetsAvailable() || _.isUndefined(this.props.onSelectAssetClick)) {
return undefined;
}
return this._handleSelectAssetClick;
};
- private readonly _areMultipleAssetsAvailable = (): boolean => {
+ private readonly _areAnyAssetsAvailable = (): boolean => {
const { numberOfAssetsAvailable } = this.props;
- return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 1;
+ return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 0;
};
private readonly _handleSelectAssetClick = (): void => {
if (this.props.onSelectAssetClick) {
diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
index 1b1921acb..f7d5a4fe4 100644
--- a/packages/instant/src/components/erc20_token_selector.tsx
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -3,6 +3,7 @@ import * as React from 'react';
import { ColorOption } from '../style/theme';
import { ERC20Asset } from '../types';
+import { analytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { SearchInput } from './search_input';
@@ -18,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;
@@ -57,13 +58,14 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
this.setState({
searchQuery,
});
+ analytics.trackTokenSelectorSearched(searchQuery);
};
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);
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/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index ace577824..117f9dd5f 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -32,7 +32,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
public render(): React.ReactNode {
const iconOrAmounts = this._renderIcon() || this._renderAmountsSection();
return (
- <Container backgroundColor={ColorOption.primaryColor} padding="20px" width="100%">
+ <Container backgroundColor={ColorOption.primaryColor} width="100%" padding="20px">
<Container marginBottom="5px">
<Text
letterSpacing="1px"
@@ -107,7 +107,14 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
private readonly _renderEthAmount = (): React.ReactNode => {
return (
- <Text fontSize="16px" textAlign="right" width="100%" fontColor={ColorOption.white} fontWeight={500}>
+ <Text
+ fontSize="16px"
+ textAlign="right"
+ width="100%"
+ fontColor={ColorOption.white}
+ fontWeight={500}
+ noWrap={true}
+ >
{format.ethBaseUnitAmount(
this.props.totalEthBaseUnitAmount,
4,
@@ -119,7 +126,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
private readonly _renderDollarAmount = (): React.ReactNode => {
return (
- <Text fontSize="16px" textAlign="right" width="100%" fontColor={ColorOption.white}>
+ <Text fontSize="16px" textAlign="right" width="100%" fontColor={ColorOption.white} noWrap={true}>
{format.ethBaseUnitAmountInUsd(
this.props.totalEthBaseUnitAmount,
this.props.ethUsdPrice,
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index 5fc956e1c..a8e0e2513 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -34,7 +34,7 @@ export class OrderDetails extends React.Component<OrderDetailsProps> {
? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil()
: undefined;
return (
- <Container padding="20px" width="100%" flexGrow={1}>
+ <Container width="100%" flexGrow={1} padding="20px 20px 0px 20px">
<Container marginBottom="10px">
<Text
letterSpacing="1px"
diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx
index ebcd62f35..7c93f1d1c 100644
--- a/packages/instant/src/components/payment_method.tsx
+++ b/packages/instant/src/components/payment_method.tsx
@@ -18,7 +18,7 @@ import { WalletPrompt } from './wallet_prompt';
export interface PaymentMethodProps {
account: Account;
network: Network;
- walletName: string;
+ walletDisplayName: string;
onInstallWalletClick: () => void;
onUnlockWalletClick: () => void;
}
@@ -26,7 +26,7 @@ export interface PaymentMethodProps {
export class PaymentMethod extends React.Component<PaymentMethodProps> {
public render(): React.ReactNode {
return (
- <Container padding="20px" width="100%">
+ <Container width="100%" height="120px" padding="20px 20px 0px 20px">
<Container marginBottom="12px">
<Flex justify="space-between">
<Text
@@ -62,11 +62,11 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> {
if (account.state === AccountState.Ready || account.state === AccountState.Locked) {
const circleColor: ColorOption = account.state === AccountState.Ready ? ColorOption.green : ColorOption.red;
return (
- <Flex>
+ <Flex align="center">
<Circle diameter={8} color={circleColor} />
- <Container marginLeft="3px">
- <Text fontColor={ColorOption.darkGrey} fontSize="12px">
- {this.props.walletName}
+ <Container marginLeft="5px">
+ <Text fontColor={ColorOption.darkGrey} fontSize="12px" lineHeight="30px">
+ {this.props.walletDisplayName}
</Text>
</Container>
</Flex>
@@ -83,16 +83,19 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> {
const colors = { primaryColor, secondaryColor };
switch (account.state) {
case AccountState.Loading:
- // Just take up the same amount of space as the other states.
- return <Container height="52px" />;
+ return null;
case AccountState.Locked:
return (
<WalletPrompt
onClick={this.props.onUnlockWalletClick}
- image={<Icon width={13} icon="lock" color={ColorOption.black} />}
+ image={
+ <Container position="relative" top="2px">
+ <Icon width={13} icon="lock" color={ColorOption.black} />
+ </Container>
+ }
{...colors}
>
- Please Unlock {this.props.walletName}
+ Click to Connect {this.props.walletDisplayName}
</WalletPrompt>
);
case AccountState.None:
diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx
index b330dbcd6..872ac0831 100644
--- a/packages/instant/src/components/payment_method_dropdown.tsx
+++ b/packages/instant/src/components/payment_method_dropdown.tsx
@@ -1,8 +1,9 @@
import { BigNumber } from '@0x/utils';
-import copy from 'copy-to-clipboard';
+import * as copy from 'copy-to-clipboard';
import * as React from 'react';
import { Network } from '../types';
+import { analytics } from '../util/analytics';
import { envUtil } from '../util/env';
import { etherscanUtil } from '../util/etherscan';
import { format } from '../util/format';
@@ -20,7 +21,14 @@ export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdown
const { accountAddress, accountEthBalanceInWei } = this.props;
const value = format.ethAddress(accountAddress);
const label = format.ethBaseUnitAmount(accountEthBalanceInWei, 4, '') as string;
- return <Dropdown value={value} label={label} items={this._getDropdownItemConfigs()} />;
+ return (
+ <Dropdown
+ value={value}
+ label={label}
+ items={this._getDropdownItemConfigs()}
+ onOpen={analytics.trackPaymentMethodDropdownOpened}
+ />
+ );
}
private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => {
if (envUtil.isMobileOperatingSystem()) {
@@ -37,11 +45,15 @@ export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdown
return [viewOnEtherscan, copyAddressToClipboard];
};
private readonly _handleEtherscanClick = (): void => {
+ analytics.trackPaymentMethodOpenedEtherscan();
+
const { accountAddress, network } = this.props;
const etherscanUrl = etherscanUtil.getEtherScanEthAddressIfExists(accountAddress, network);
window.open(etherscanUrl, '_blank');
};
private readonly _handleCopyToClipboardClick = (): void => {
+ analytics.trackPaymentMethodCopiedAddress();
+
const { accountAddress } = this.props;
copy(accountAddress);
};
diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx
index 0861bbe05..86aca5a65 100644
--- a/packages/instant/src/components/scaling_amount_input.tsx
+++ b/packages/instant/src/components/scaling_amount_input.tsx
@@ -4,6 +4,7 @@ import * as React from 'react';
import { Maybe } from '../types';
+import { GIT_SHA, MAGIC_TRIGGER_ERROR_INPUT, MAGIC_TRIGGER_ERROR_MESSAGE, NPM_PACKAGE_VERSION } from '../constants';
import { ColorOption } from '../style/theme';
import { maybeBigNumberUtil } from '../util/maybe_big_number';
import { util } from '../util/util';
@@ -71,6 +72,10 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps,
);
}
private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
+ if (event.target.value === MAGIC_TRIGGER_ERROR_INPUT) {
+ throw new Error(`${MAGIC_TRIGGER_ERROR_MESSAGE} git: ${GIT_SHA}, npm: ${NPM_PACKAGE_VERSION}`);
+ }
+
const sanitizedValue = event.target.value.replace(/[^0-9.]/g, ''); // only allow numbers and "."
this.setState({
stringValue: sanitizedValue,
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,
diff --git a/packages/instant/src/components/search_input.tsx b/packages/instant/src/components/search_input.tsx
index 3a693b9f8..71bc18915 100644
--- a/packages/instant/src/components/search_input.tsx
+++ b/packages/instant/src/components/search_input.tsx
@@ -13,10 +13,10 @@ export interface SearchInputProps extends InputProps {
}
export const SearchInput: React.StatelessComponent<SearchInputProps> = props => (
- <Container backgroundColor={props.backgroundColor} borderRadius="3px" padding=".5em .3em">
- <Flex justify="flex-start" align="flex-end">
- <Icon width={14} height={14} icon="search" color={ColorOption.lightGrey} padding="0px 12px" />
- <Input {...props} fontSize="14px" fontColor={props.fontColor} />
+ <Container backgroundColor={props.backgroundColor} borderRadius="3px" padding=".5em .5em">
+ <Flex justify="flex-start" align="center">
+ <Icon width={14} height={14} icon="search" color={ColorOption.lightGrey} padding="2px 12px" />
+ <Input {...props} type="search" fontSize="16px" fontColor={props.fontColor} />
</Flex>
</Container>
);
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/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx
index f587ff79a..9f517d273 100644
--- a/packages/instant/src/components/standard_sliding_panel.tsx
+++ b/packages/instant/src/components/standard_sliding_panel.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
-import { SlideAnimationState, StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types';
+import { StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types';
import { InstallWalletPanelContent } from './install_wallet_panel_content';
import { SlidingPanel } from './sliding_panel';
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..636eb8fc9 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -27,7 +27,9 @@ export interface ContainerProps {
borderBottom?: string;
className?: string;
backgroundColor?: ColorOption;
+ rawBackgroundColor?: string;
hasBoxShadow?: boolean;
+ isHidden?: boolean;
zIndex?: number;
whiteSpace?: string;
opacity?: number;
@@ -38,6 +40,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 >
@@ -65,12 +77,14 @@ export const Container =
${props => cssRuleIfExists(props, 'opacity')}
${props => cssRuleIfExists(props, 'cursor')}
${props => cssRuleIfExists(props, 'overflow')}
+ ${props => (props.overflow === 'scroll' ? `-webkit-overflow-scrolling: touch` : '')};
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
${props => props.display && stylesForMedia<string>('display', props.display)}
${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')};
+ ${props => (props.isHidden ? 'visibility: hidden;' : '')}
+ 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/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx
index 3a23f456d..02e87d639 100644
--- a/packages/instant/src/components/ui/dropdown.tsx
+++ b/packages/instant/src/components/ui/dropdown.tsx
@@ -19,6 +19,7 @@ export interface DropdownProps {
value: string;
label?: string;
items: DropdownItemConfig[];
+ onOpen?: () => void;
}
export interface DropdownState {
@@ -97,9 +98,14 @@ export class Dropdown extends React.Component<DropdownProps, DropdownState> {
if (_.isEmpty(this.props.items)) {
return;
}
+ const isOpen = !this.state.isOpen;
this.setState({
- isOpen: !this.state.isOpen,
+ isOpen,
});
+
+ if (isOpen && this.props.onOpen) {
+ this.props.onOpen();
+ }
};
private readonly _closeDropdown = (): void => {
this.setState({
diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx
index 1ea5d8fe1..863c970ef 100644
--- a/packages/instant/src/components/ui/input.tsx
+++ b/packages/instant/src/components/ui/input.tsx
@@ -10,6 +10,7 @@ export interface InputProps {
fontSize?: string;
fontColor?: ColorOption;
placeholder?: string;
+ type?: string;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx
index f67d6fb2f..0b5eaf299 100644
--- a/packages/instant/src/components/ui/overlay.tsx
+++ b/packages/instant/src/components/ui/overlay.tsx
@@ -33,7 +33,7 @@ export const Overlay =
Overlay.defaultProps = {
zIndex: zIndex.overlayDefault,
- backgroundColor: generateOverlayBlack(0.6),
+ backgroundColor: generateOverlayBlack(0.7),
};
Overlay.displayName = 'Overlay';
diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx
index 8e573d7b9..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';
@@ -31,7 +30,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 +55,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};` : '')};
}
}
`;
diff --git a/packages/instant/src/components/wallet_prompt.tsx b/packages/instant/src/components/wallet_prompt.tsx
index a0b3ae457..c07cfe7b5 100644
--- a/packages/instant/src/components/wallet_prompt.tsx
+++ b/packages/instant/src/components/wallet_prompt.tsx
@@ -21,7 +21,7 @@ export const WalletPrompt: React.StatelessComponent<WalletPromptProps> = ({
primaryColor,
}) => (
<Container
- padding="14.5px"
+ padding="10px"
border={`1px solid ${primaryColor}`}
backgroundColor={secondaryColor}
width="100%"
@@ -33,7 +33,7 @@ export const WalletPrompt: React.StatelessComponent<WalletPromptProps> = ({
<Flex>
{image}
<Container marginLeft="10px">
- <Text fontSize="16px" fontColor={primaryColor}>
+ <Text fontSize="16px" fontColor={primaryColor} fontWeight="500">
{children}
</Text>
</Container>
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index 47c938472..0337c7714 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -11,21 +11,20 @@ import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_
import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
import { ColorOption } from '../style/theme';
import { zIndex } from '../style/z_index';
-import { OrderProcessState, SlideAnimationState } from '../types';
+import { SlideAnimationState } from '../types';
+import { analytics, TokenSelectorClosedVia } from '../util/analytics';
import { CSSReset } from './css_reset';
import { SlidingPanel } from './sliding_panel';
import { Container } from './ui/container';
import { Flex } from './ui/flex';
-export interface ZeroExInstantContainerProps {
- orderProcessState: OrderProcessState;
-}
+export interface ZeroExInstantContainerProps {}
export interface ZeroExInstantContainerState {
tokenSelectionPanelAnimationState: SlideAnimationState;
}
-export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantContainerState> {
+export class ZeroExInstantContainer extends React.Component<ZeroExInstantContainerProps, ZeroExInstantContainerState> {
public state = {
tokenSelectionPanelAnimationState: 'none' as SlideAnimationState,
};
@@ -60,9 +59,9 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon
</Flex>
<SlidingPanel
animationState={this.state.tokenSelectionPanelAnimationState}
- onClose={this._handlePanelClose}
+ onClose={this._handlePanelCloseClickedX}
>
- <AvailableERC20TokenSelector onTokenSelect={this._handlePanelClose} />
+ <AvailableERC20TokenSelector onTokenSelect={this._handlePanelCloseAfterChose} />
</SlidingPanel>
<CurrentStandardSlidingPanel />
</Container>
@@ -71,7 +70,7 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon
marginTop="10px"
marginLeft="auto"
marginRight="auto"
- width="140px"
+ width="108px"
>
<a href={ZERO_EX_SITE_URL} target="_blank">
<PoweredByLogo />
@@ -82,11 +81,19 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon
);
}
private readonly _handleSymbolClick = (): void => {
+ analytics.trackTokenSelectorOpened();
this.setState({
tokenSelectionPanelAnimationState: 'slidIn',
});
};
- private readonly _handlePanelClose = (): void => {
+ private readonly _handlePanelCloseClickedX = (): void => {
+ this._handlePanelClose(TokenSelectorClosedVia.ClickedX);
+ };
+ private readonly _handlePanelCloseAfterChose = (): void => {
+ this._handlePanelClose(TokenSelectorClosedVia.TokenChose);
+ };
+ private readonly _handlePanelClose = (closedVia: TokenSelectorClosedVia): void => {
+ analytics.trackTokenSelectorClosed(closedVia);
this.setState({
tokenSelectionPanelAnimationState: 'slidOut',
});
diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx
index 2856ea3e3..96e560691 100644
--- a/packages/instant/src/components/zero_ex_instant_overlay.tsx
+++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { ZeroExInstantContainer } from '../components/zero_ex_instant_container';
+import { MAIN_CONTAINER_DIV_CLASS, OVERLAY_CLOSE_BUTTON_DIV_CLASS, OVERLAY_DIV_CLASS } from '../constants';
import { ColorOption } from '../style/theme';
import { Container } from './ui/container';
@@ -18,9 +19,15 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay
const { onClose, zIndex, ...rest } = props;
return (
<ZeroExInstantProvider {...rest}>
- <Overlay zIndex={zIndex}>
+ <Overlay zIndex={zIndex} className={OVERLAY_DIV_CLASS}>
<Flex height="100vh">
- <Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}>
+ <Container
+ className={OVERLAY_CLOSE_BUTTON_DIV_CLASS}
+ position="absolute"
+ top="0px"
+ right="0px"
+ display={{ default: 'initial', sm: 'none' }}
+ >
<Icon
height={18}
width={18}
@@ -30,7 +37,11 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay
padding="2em 2em"
/>
</Container>
- <Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}>
+ <Container
+ width={{ default: 'auto', sm: '100%' }}
+ height={{ default: 'auto', sm: '100%' }}
+ className={MAIN_CONTAINER_DIV_CLASS}
+ >
<ZeroExInstantContainer />
</Container>
</Flex>
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index fe34c4466..dae9124c6 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -11,10 +11,11 @@ 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, QuoteFetchOrigin } from '../types';
import { analytics, disableAnalytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { errorFlasher } from '../util/error_flasher';
+import { setupRollbar } from '../util/error_reporter';
import { gasPriceEstimator } from '../util/gas_price_estimator';
import { Heartbeater } from '../util/heartbeater';
import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory';
@@ -29,6 +30,7 @@ export interface ZeroExInstantProviderRequiredProps {
export interface ZeroExInstantProviderOptionalProps {
provider: Provider;
+ walletDisplayName: string;
availableAssetDatas: string[];
defaultAssetBuyAmount: number;
defaultSelectedAssetData: string;
@@ -66,6 +68,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
...defaultState,
providerState,
network: networkId,
+ walletDisplayName: props.walletDisplayName,
selectedAsset: _.isUndefined(props.defaultSelectedAssetData)
? undefined
: assetUtils.createAssetFromAssetDataOrThrow(
@@ -86,6 +89,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
}
constructor(props: ZeroExInstantProviderProps) {
super(props);
+ setupRollbar();
fonts.include();
const initialAppState = ZeroExInstantProvider._mergeDefaultStateWithProps(this.props);
this._store = store.create(initialAppState);
@@ -115,7 +119,9 @@ 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, QuoteFetchOrigin.Manual, {
+ updateSilently: false,
+ });
// 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
@@ -131,6 +137,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
this.props.orderSource,
state.providerState,
window,
+ state.selectedAsset,
this.props.affiliateInfo,
),
);
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index be6077ca9..506348092 100644
--- a/packages/instant/src/constants.ts
+++ b/packages/instant/src/constants.ts
@@ -7,19 +7,42 @@ export const ETH_DECIMALS = 18;
export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer';
export const INJECTED_DIV_CLASS = 'zeroExInstantResetRoot';
export const INJECTED_DIV_ID = 'zeroExInstant';
+export const OVERLAY_DIV_CLASS = 'zeroExInstantOverlay';
+export const OVERLAY_CLOSE_BUTTON_DIV_CLASS = 'zeroExInstantOverlayCloseButton';
+export const MAIN_CONTAINER_DIV_CLASS = 'zeroExInstantMainContainer';
export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed';
export const GWEI_IN_WEI = new BigNumber(1000000000);
export const ONE_SECOND_MS = 1000;
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
+export const GIT_SHA = process.env.GIT_SHA;
+export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION;
export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5;
export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15;
export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6);
export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
+export const MAGIC_TRIGGER_ERROR_INPUT = '0€';
+export const MAGIC_TRIGGER_ERROR_MESSAGE = 'Triggered error';
export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID;
+export const HEAP_ENABLED = process.env.HEAP_ENABLED;
export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2';
export const PROGRESS_STALL_AT_WIDTH = '95%';
export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200;
+export const HOST_DOMAINS = [
+ '0x-instant-staging.s3-website-us-east-1.amazonaws.com',
+ '0x-instant-dogfood.s3-website-us-east-1.amazonaws.com',
+ 'localhost',
+ '127.0.0.1',
+ '0.0.0.0',
+ 'instant.0xproject.com',
+];
+export const ROLLBAR_CLIENT_TOKEN = process.env.ROLLBAR_CLIENT_TOKEN;
+export const ROLLBAR_ENABLED = process.env.ROLLBAR_ENABLED;
+export const INSTANT_DISCHARGE_TARGET = process.env.INSTANT_DISCHARGE_TARGET as
+ | 'production'
+ | 'dogfood'
+ | 'staging'
+ | undefined;
export const COINBASE_WALLET_IOS_APP_STORE_URL = 'https://itunes.apple.com/us/app/coinbase-wallet/id1278383455?mt=8';
export const COINBASE_WALLET_ANDROID_APP_STORE_URL = 'https://play.google.com/store/apps/details?id=org.toshi&hl=en';
export const COINBASE_WALLET_SITE_URL = 'https://wallet.coinbase.com/';
diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts
index cdeb49a25..bb68fdd57 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';
@@ -20,6 +20,7 @@ export interface ConnectedAccountPaymentMethodProps {}
interface ConnectedState {
network: Network;
providerState: ProviderState;
+ walletDisplayName?: string;
}
interface ConnectedDispatch {
@@ -34,6 +35,7 @@ type FinalProps = ConnectedProps & ConnectedAccountPaymentMethodProps;
const mapStateToProps = (state: State, _ownProps: ConnectedAccountPaymentMethodProps): ConnectedState => ({
network: state.network,
providerState: state.providerState,
+ walletDisplayName: state.walletDisplayName,
});
const mapDispatchToProps = (
@@ -56,27 +58,32 @@ const mergeProps = (
...ownProps,
network: connectedState.network,
account: connectedState.providerState.account,
- walletName: connectedState.providerState.name,
+ walletDisplayName: connectedState.walletDisplayName || connectedState.providerState.name,
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/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx
index b7cfdb504..0d4349124 100644
--- a/packages/instant/src/containers/latest_error.tsx
+++ b/packages/instant/src/containers/latest_error.tsx
@@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { SlidingError } from '../components/sliding_error';
+import { Container } from '../components/ui/container';
import { Overlay } from '../components/ui/overlay';
import { Action } from '../redux/actions';
import { State } from '../redux/reducer';
@@ -23,7 +24,12 @@ export interface LatestErrorComponentProps {
export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
if (!props.latestErrorMessage) {
- return <div />;
+ // Render a hidden SlidingError such that instant does not move when a real error is rendered.
+ return (
+ <Container isHidden={true}>
+ <SlidingError animationState="slidIn" icon="😢" message="" />
+ </Container>
+ );
}
return (
<React.Fragment>
diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
index 610335243..80943a96f 100644
--- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
+++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
@@ -9,7 +9,8 @@ import { Dispatch } from 'redux';
import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
-import { AccountState, AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
+import { AccountState, AffiliateInfo, Asset, OrderProcessState, ZeroExInstantError } from '../types';
+import { analytics } from '../util/analytics';
import { errorFlasher } from '../util/error_flasher';
import { etherscanUtil } from '../util/etherscan';
@@ -21,6 +22,7 @@ interface ConnectedState {
assetBuyer: AssetBuyer;
web3Wrapper: Web3Wrapper;
affiliateInfo?: AffiliateInfo;
+ selectedAsset?: Asset;
onViewTransaction: () => void;
}
@@ -40,6 +42,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt
const account = state.providerState.account;
const accountAddress = account.state === AccountState.Ready ? account.address : undefined;
const accountEthBalanceInWei = account.state === AccountState.Ready ? account.ethBalanceInWei : undefined;
+ const selectedAsset = state.selectedAsset;
return {
accountAddress,
accountEthBalanceInWei,
@@ -48,6 +51,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt
web3Wrapper,
buyQuote: state.latestBuyQuote,
affiliateInfo: state.affiliateInfo,
+ selectedAsset,
onViewTransaction: () => {
if (
state.buyOrderState.processState === OrderProcessState.Processing ||
@@ -59,6 +63,8 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt
assetBuyer.networkId,
);
if (etherscanUrl) {
+ analytics.trackTransactionViewed(state.buyOrderState.processState);
+
window.open(etherscanUrl, '_blank');
return;
}
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..cb9df527e 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, QuoteFetchOrigin } from '../types';
import { buyQuoteUpdater } from '../util/buy_quote_updater';
export interface SelectedERC20AssetAmountInputProps {
@@ -88,7 +88,7 @@ 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,
diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts
index b24c9c83d..88611a8c0 100644
--- a/packages/instant/src/data/asset_meta_data_map.ts
+++ b/packages/instant/src/data/asset_meta_data_map.ts
@@ -83,14 +83,14 @@ export const assetMetaDataMap: ObjectMap<AssetMetaData> = {
'0xf47261b0000000000000000000000000e0b7927c4af23765cb51314a0e0521a9645f0e2a': {
assetProxyId: AssetProxyId.ERC20,
decimals: 9,
- primaryColor: '#DEB564',
+ primaryColor: '#E1AA3E',
symbol: 'dgd',
name: 'DigixDao',
},
'0xf47261b00000000000000000000000004f3afec4e5a3f2a6a1a411def7d7dfe50ee057bf': {
assetProxyId: AssetProxyId.ERC20,
decimals: 9,
- primaryColor: '#DEB564',
+ primaryColor: '#E1AA3E',
symbol: 'dgx',
name: 'Digix Gold Token',
},
@@ -195,7 +195,7 @@ export const assetMetaDataMap: ObjectMap<AssetMetaData> = {
'0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359': {
assetProxyId: AssetProxyId.ERC20,
decimals: 18,
- primaryColor: '#F2B350',
+ primaryColor: '#DEA349',
symbol: 'dai',
name: 'Dai Stablecoin',
},
diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts
index 3a8694d6a..d172f4145 100644
--- a/packages/instant/src/index.umd.ts
+++ b/packages/instant/src/index.umd.ts
@@ -2,8 +2,15 @@ import * as _ from 'lodash';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
-import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants';
+import {
+ DEFAULT_ZERO_EX_CONTAINER_SELECTOR,
+ GIT_SHA as GIT_SHA_FROM_CONSTANT,
+ INJECTED_DIV_CLASS,
+ INJECTED_DIV_ID,
+ NPM_PACKAGE_VERSION,
+} from './constants';
import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index';
+import { analytics } from './util/analytics';
import { assert } from './util/assert';
import { util } from './util/util';
@@ -38,6 +45,9 @@ const validateInstantRenderConfig = (config: ZeroExInstantConfig, selector: stri
if (!_.isUndefined(config.provider)) {
assert.isWeb3Provider('provider', config.provider);
}
+ if (!_.isUndefined(config.walletDisplayName)) {
+ assert.isString('walletDisplayName', config.walletDisplayName);
+ }
if (!_.isUndefined(config.shouldDisablePushToHistory)) {
assert.isBoolean('shouldDisablePushToHistory', config.shouldDisablePushToHistory);
}
@@ -57,6 +67,7 @@ const renderInstant = (config: ZeroExInstantConfig, selector: string) => {
injectedDiv.setAttribute('class', INJECTED_DIV_CLASS);
appendTo.appendChild(injectedDiv);
const closeInstant = () => {
+ analytics.trackInstantClosed();
if (!_.isUndefined(config.onClose)) {
config.onClose();
}
@@ -89,12 +100,12 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z
// If the integrator defined a popstate handler, save it to __zeroExInstantIntegratorsPopStateHandler
// unless we have already done so on a previous render.
const anyWindow = window as any;
- if (window.onpopstate && !anyWindow.__zeroExInstantIntegratorsPopStateHandler) {
- anyWindow.__zeroExInstantIntegratorsPopStateHandler = window.onpopstate.bind(window);
- }
- const integratorsOnPopStateHandler = anyWindow.__zeroExInstantIntegratorsPopStateHandler || util.boundNoop;
+ const popStateExistsAndNotSetPreviously = window.onpopstate && !anyWindow.__zeroExInstantIntegratorsPopStateHandler;
+ anyWindow.__zeroExInstantIntegratorsPopStateHandler = popStateExistsAndNotSetPreviously
+ ? anyWindow.onpopstate.bind(window)
+ : util.boundNoop;
const onPopStateHandler = (e: PopStateEvent) => {
- integratorsOnPopStateHandler(e);
+ anyWindow.__zeroExInstantIntegratorsPopStateHandler(e);
const newState = e.state;
if (newState && newState.zeroExInstantShowing) {
// We have returned to a history state that expects instant to be rendered.
@@ -110,3 +121,7 @@ export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_Z
};
window.onpopstate = onPopStateHandler;
};
+
+// Write version info to the exported object for debugging
+export const GIT_SHA = GIT_SHA_FROM_CONSTANT;
+export const NPM_VERSION = NPM_PACKAGE_VERSION;
diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts
index 299c2560e..3f7a51707 100644
--- a/packages/instant/src/redux/analytics_middleware.ts
+++ b/packages/instant/src/redux/analytics_middleware.ts
@@ -1,10 +1,11 @@
+import { AssetProxyId } from '@0x/types';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import { Middleware } from 'redux';
import { ETH_DECIMALS } from '../constants';
-import { Account, AccountState } from '../types';
-import { analytics } from '../util/analytics';
+import { AccountState, StandardSlidingPanelContent } from '../types';
+import { analytics, AnalyticsEventOptions } from '../util/analytics';
import { Action, ActionTypes } from './actions';
@@ -29,9 +30,11 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction
if (didJustTurnReady) {
analytics.trackAccountReady(ethAddress);
analytics.addUserProperties({ lastKnownEthAddress: ethAddress });
+ analytics.addEventProperties({ ethAddress });
} else if (didJustUpdateAddress) {
analytics.trackAccountAddressChanged(ethAddress);
analytics.addUserProperties({ lastKnownEthAddress: ethAddress });
+ analytics.addEventProperties({ ethAddress });
}
}
break;
@@ -51,8 +54,51 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction
curAccount.ethBalanceInWei,
ETH_DECIMALS,
).toString();
- analytics.addUserProperties({ ethBalanceInUnitAmount });
+ analytics.addUserProperties({ lastEthBalanceInUnitAmount: ethBalanceInUnitAmount });
+ analytics.addEventProperties({ ethBalanceInUnitAmount });
}
+ break;
+ case ActionTypes.UPDATE_SELECTED_ASSET:
+ const selectedAsset = curState.selectedAsset;
+ if (selectedAsset) {
+ const assetName = selectedAsset.metaData.name;
+ const assetData = selectedAsset.assetData;
+ analytics.trackTokenSelectorChose({
+ assetName,
+ assetData,
+ });
+
+ const selectedAssetEventProperties: AnalyticsEventOptions = {
+ selectedAssetName: assetName,
+ selectedAssetData: assetData,
+ };
+ if (selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20) {
+ selectedAssetEventProperties.selectedAssetDecimals = selectedAsset.metaData.decimals;
+ selectedAssetEventProperties.selectedAssetSymbol = selectedAsset.metaData.symbol;
+ }
+ analytics.addEventProperties(selectedAssetEventProperties);
+ }
+ break;
+ case ActionTypes.SET_AVAILABLE_ASSETS:
+ const availableAssets = curState.availableAssets;
+ if (availableAssets) {
+ analytics.addEventProperties({
+ numberAvailableAssets: availableAssets.length,
+ });
+ }
+ 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/redux/async_data.ts b/packages/instant/src/redux/async_data.ts
index 6feb760e7..c67b222d1 100644
--- a/packages/instant/src/redux/async_data.ts
+++ b/packages/instant/src/redux/async_data.ts
@@ -4,12 +4,13 @@ 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, QuoteFetchOrigin } from '../types';
import { analytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { buyQuoteUpdater } from '../util/buy_quote_updater';
import { coinbaseApi } from '../util/coinbase_api';
import { errorFlasher } from '../util/error_flasher';
+import { errorReporter } from '../util/error_reporter';
import { actions } from './actions';
import { State } from './reducer';
@@ -23,6 +24,7 @@ export const asyncData = {
const errorMessage = 'Error fetching ETH/USD price';
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO));
+ errorReporter.report(e);
}
},
fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => {
@@ -30,13 +32,15 @@ export const asyncData = {
const assetBuyer = providerState.assetBuyer;
try {
const assetDatas = await assetBuyer.getAvailableAssetDatasAsync();
- const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network);
+ const deduplicatedAssetDatas = _.uniq(assetDatas);
+ const assets = assetUtils.createAssetsFromAssetDatas(deduplicatedAssetDatas, assetMetaDataMap, network);
dispatch(actions.setAvailableAssets(assets));
} catch (e) {
const errorMessage = 'Could not find any assets';
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
// On error, just specify that none are available
dispatch(actions.setAvailableAssets([]));
+ errorReporter.report(e);
}
},
fetchAccountInfoAndDispatchToStore: async (
@@ -77,6 +81,7 @@ export const asyncData = {
const ethBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(address);
dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei }));
} catch (e) {
+ errorReporter.report(e);
// leave balance as is
return;
}
@@ -84,6 +89,7 @@ export const asyncData = {
fetchCurrentBuyQuoteAndDispatchToStore: async (
state: State,
dispatch: Dispatch,
+ fetchOrigin: QuoteFetchOrigin,
options: { updateSilently: boolean },
) => {
const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
@@ -99,7 +105,12 @@ export const asyncData = {
dispatch,
selectedAsset as ERC20Asset,
selectedAssetUnitAmount,
- { setPending: !options.updateSilently, dispatchErrors: !options.updateSilently, affiliateInfo },
+ fetchOrigin,
+ {
+ setPending: !options.updateSilently,
+ dispatchErrors: !options.updateSilently,
+ affiliateInfo,
+ },
);
}
},
diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts
index dfc2b89f3..a9a407b7d 100644
--- a/packages/instant/src/redux/reducer.ts
+++ b/packages/instant/src/redux/reducer.ts
@@ -49,6 +49,7 @@ interface OptionalState {
latestBuyQuote: BuyQuote;
latestErrorMessage: string;
affiliateInfo: AffiliateInfo;
+ walletDisplayName: string;
}
export type State = DefaultState & PropsDerivedState & Partial<OptionalState>;
diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts
index a0751286b..fd3f03c3f 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 };
@@ -30,8 +38,8 @@ export const theme: Theme = {
lightestGrey: '#EEEEEE',
darkGrey: '#333333',
white: 'white',
- lightOrange: '#F9F2ED',
- darkOrange: '#F2994C',
+ lightOrange: '#FFF8F2',
+ darkOrange: '#F7A24F',
green: '#3CB34F',
red: '#D00000',
darkBlue: '#135df6',
@@ -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 };
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index 999d50fed..2d73ba29e 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -21,6 +21,11 @@ export enum OrderProcessState {
Failure = 'FAILURE',
}
+export enum QuoteFetchOrigin {
+ Manual = 'Manual',
+ Heartbeat = 'Heartbeat',
+}
+
export interface SimulatedProgress {
startTimeUnix: number;
expectedEndTimeUnix: number;
@@ -149,6 +154,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 cec99dd1b..6da37bedb 100644
--- a/packages/instant/src/util/analytics.ts
+++ b/packages/instant/src/util/analytics.ts
@@ -1,26 +1,66 @@
-import { AffiliateInfo, Network, OrderSource, ProviderState } from '../types';
+import { BuyQuote } from '@0x/asset-buyer';
+import { BigNumber } from '@0x/utils';
+import * as _ from 'lodash';
+
+import { GIT_SHA, HEAP_ENABLED, INSTANT_DISCHARGE_TARGET, NPM_PACKAGE_VERSION } from '../constants';
+import {
+ AffiliateInfo,
+ Asset,
+ Network,
+ OrderProcessState,
+ OrderSource,
+ ProviderState,
+ QuoteFetchOrigin,
+ WalletSuggestion,
+} from '../types';
import { EventProperties, heapUtil } from './heap';
-let isDisabled = false;
+let isDisabledViaConfig = false;
export const disableAnalytics = (shouldDisableAnalytics: boolean) => {
- isDisabled = shouldDisableAnalytics;
+ isDisabledViaConfig = shouldDisableAnalytics;
};
export const evaluateIfEnabled = (fnCall: () => void) => {
- if (isDisabled) {
+ if (isDisabledViaConfig) {
return;
}
- fnCall();
+ if (HEAP_ENABLED) {
+ fnCall();
+ }
};
enum EventNames {
INSTANT_OPENED = 'Instant - Opened',
+ INSTANT_CLOSED = 'Instant - Closed',
ACCOUNT_LOCKED = 'Account - Locked',
ACCOUNT_READY = 'Account - Ready',
ACCOUNT_UNLOCK_REQUESTED = 'Account - Unlock Requested',
ACCOUNT_UNLOCK_DENIED = 'Account - Unlock Denied',
ACCOUNT_ADDRESS_CHANGED = 'Account - Address Changed',
+ PAYMENT_METHOD_DROPDOWN_OPENED = 'Payment Method - Dropdown Opened',
+ PAYMENT_METHOD_OPENED_ETHERSCAN = 'Payment Method - Opened Etherscan',
+ PAYMENT_METHOD_COPIED_ADDRESS = 'Payment Method - Copied Address',
+ BUY_NOT_ENOUGH_ETH = 'Buy - Not Enough Eth',
+ BUY_STARTED = 'Buy - Started',
+ BUY_SIGNATURE_DENIED = 'Buy - Signature Denied',
+ BUY_SIMULATION_FAILED = 'Buy - Simulation Failed',
+ BUY_TX_SUBMITTED = 'Buy - Tx Submitted',
+ 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',
+ TOKEN_SELECTOR_SEARCHED = 'Token Selector - Searched',
+ TRANSACTION_VIEWED = 'Transaction - Viewed',
+ QUOTE_FETCHED = 'Quote - Fetched',
+ QUOTE_ERROR = 'Quote - Error',
}
+
const track = (eventName: EventNames, eventProperties: EventProperties = {}): void => {
evaluateIfEnabled(() => {
heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventProperties));
@@ -38,22 +78,50 @@ function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: Ev
};
}
+const buyQuoteEventProperties = (buyQuote: BuyQuote) => {
+ const assetBuyAmount = buyQuote.assetBuyAmount.toString();
+ const assetEthAmount = buyQuote.worstCaseQuoteInfo.assetEthAmount.toString();
+ const feeEthAmount = buyQuote.worstCaseQuoteInfo.feeEthAmount.toString();
+ const totalEthAmount = buyQuote.worstCaseQuoteInfo.totalEthAmount.toString();
+ const feePercentage = !_.isUndefined(buyQuote.feePercentage) ? buyQuote.feePercentage.toString() : 0;
+ const hasFeeOrders = !_.isEmpty(buyQuote.feeOrders) ? 'true' : 'false';
+ return {
+ assetBuyAmount,
+ assetEthAmount,
+ feeEthAmount,
+ totalEthAmount,
+ feePercentage,
+ hasFeeOrders,
+ };
+};
+
export interface AnalyticsUserOptions {
lastKnownEthAddress?: string;
- ethBalanceInUnitAmount?: string;
+ lastEthBalanceInUnitAmount?: string;
}
export interface AnalyticsEventOptions {
embeddedHost?: string;
embeddedUrl?: string;
+ ethBalanceInUnitAmount?: string;
+ ethAddress?: string;
networkId?: number;
providerName?: string;
gitSha?: string;
npmVersion?: string;
+ instantEnvironment?: string;
orderSource?: string;
affiliateAddress?: string;
affiliateFeePercent?: number;
+ numberAvailableAssets?: number;
+ selectedAssetName?: string;
+ selectedAssetSymbol?: string;
+ selectedAssetData?: string;
+ selectedAssetDecimals?: number;
+}
+export enum TokenSelectorClosedVia {
+ ClickedX = 'Clicked X',
+ TokenChose = 'Token Chose',
}
-
export const analytics = {
addUserProperties: (properties: AnalyticsUserOptions): void => {
evaluateIfEnabled(() => {
@@ -70,28 +138,94 @@ export const analytics = {
orderSource: OrderSource,
providerState: ProviderState,
window: Window,
+ selectedAsset?: Asset,
affiliateInfo?: AffiliateInfo,
): AnalyticsEventOptions => {
const affiliateAddress = affiliateInfo ? affiliateInfo.feeRecipient : 'none';
const affiliateFeePercent = affiliateInfo ? parseFloat(affiliateInfo.feePercentage.toFixed(4)) : 0;
const orderSourceName = typeof orderSource === 'string' ? orderSource : 'provided';
- return {
+ const eventOptions: AnalyticsEventOptions = {
embeddedHost: window.location.host,
embeddedUrl: window.location.href,
networkId: network,
providerName: providerState.name,
- gitSha: process.env.GIT_SHA,
- npmVersion: process.env.NPM_PACKAGE_VERSION,
+ gitSha: GIT_SHA,
+ npmVersion: NPM_PACKAGE_VERSION,
orderSource: orderSourceName,
affiliateAddress,
affiliateFeePercent,
+ selectedAssetName: selectedAsset ? selectedAsset.metaData.name : 'none',
+ selectedAssetData: selectedAsset ? selectedAsset.assetData : 'none',
+ instantEnvironment: INSTANT_DISCHARGE_TARGET || `Local ${process.env.NODE_ENV}`,
};
+ return eventOptions;
},
trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED),
+ trackInstantClosed: trackingEventFnWithoutPayload(EventNames.INSTANT_CLOSED),
trackAccountLocked: trackingEventFnWithoutPayload(EventNames.ACCOUNT_LOCKED),
trackAccountReady: (address: string) => trackingEventFnWithPayload(EventNames.ACCOUNT_READY)({ address }),
trackAccountUnlockRequested: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_REQUESTED),
trackAccountUnlockDenied: trackingEventFnWithoutPayload(EventNames.ACCOUNT_UNLOCK_DENIED),
trackAccountAddressChanged: (address: string) =>
trackingEventFnWithPayload(EventNames.ACCOUNT_ADDRESS_CHANGED)({ address }),
+ trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_DROPDOWN_OPENED),
+ trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_OPENED_ETHERSCAN),
+ trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_COPIED_ADDRESS),
+ trackBuyNotEnoughEth: (buyQuote: BuyQuote) =>
+ trackingEventFnWithPayload(EventNames.BUY_NOT_ENOUGH_ETH)(buyQuoteEventProperties(buyQuote)),
+ trackBuyStarted: (buyQuote: BuyQuote) =>
+ trackingEventFnWithPayload(EventNames.BUY_STARTED)(buyQuoteEventProperties(buyQuote)),
+ trackBuySignatureDenied: (buyQuote: BuyQuote) =>
+ trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)),
+ trackBuySimulationFailed: (buyQuote: BuyQuote) =>
+ trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)),
+ trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
+ trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({
+ ...buyQuoteEventProperties(buyQuote),
+ txHash,
+ expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
+ }),
+ trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
+ trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({
+ ...buyQuoteEventProperties(buyQuote),
+ txHash,
+ expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
+ actualTxTimeMs: new Date().getTime() - startTimeUnix,
+ }),
+ trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
+ trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({
+ ...buyQuoteEventProperties(buyQuote),
+ txHash,
+ expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
+ actualTxTimeMs: new Date().getTime() - startTimeUnix,
+ }),
+ 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 }),
+ trackTokenSelectorChose: (payload: { assetName: string; assetData: string }) =>
+ trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CHOSE)(payload),
+ trackTokenSelectorSearched: (searchText: string) =>
+ trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_SEARCHED)({ searchText }),
+ trackTransactionViewed: (orderProcesState: OrderProcessState) =>
+ trackingEventFnWithPayload(EventNames.TRANSACTION_VIEWED)({ orderState: orderProcesState }),
+ trackQuoteFetched: (buyQuote: BuyQuote, fetchOrigin: QuoteFetchOrigin) =>
+ trackingEventFnWithPayload(EventNames.QUOTE_FETCHED)({
+ ...buyQuoteEventProperties(buyQuote),
+ fetchOrigin,
+ }),
+ trackQuoteError: (errorMessage: string, assetBuyAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => {
+ trackingEventFnWithPayload(EventNames.QUOTE_ERROR)({
+ errorMessage,
+ assetBuyAmount: assetBuyAmount.toString(),
+ fetchOrigin,
+ });
+ },
};
diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts
index 40560d3eb..08f3642e3 100644
--- a/packages/instant/src/util/asset.ts
+++ b/packages/instant/src/util/asset.ts
@@ -1,3 +1,4 @@
+import { AssetBuyerError } from '@0x/asset-buyer';
import { AssetProxyId, ObjectMap } from '@0x/types';
import * as _ from 'lodash';
@@ -106,4 +107,20 @@ export const assetUtils = {
);
return _.compact(erc20sOrUndefined);
},
+ assetBuyerErrorMessage: (asset: ERC20Asset, error: Error): string | undefined => {
+ if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
+ const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
+ return `Not enough ${assetName} available`;
+ } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
+ return 'Not enough ZRX available';
+ } else if (
+ error.message === AssetBuyerError.StandardRelayerApiError ||
+ error.message.startsWith(AssetBuyerError.AssetUnavailable)
+ ) {
+ const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
+ return `${assetName} is currently unavailable`;
+ }
+
+ return undefined;
+ },
};
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 2fd16d781..4229f2735 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -1,4 +1,4 @@
-import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
+import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
@@ -6,9 +6,11 @@ import { Dispatch } from 'redux';
import { oc } from 'ts-optchain';
import { Action, actions } from '../redux/actions';
-import { AffiliateInfo, ERC20Asset } from '../types';
+import { AffiliateInfo, ERC20Asset, QuoteFetchOrigin } from '../types';
+import { analytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { errorFlasher } from '../util/error_flasher';
+import { errorReporter } from '../util/error_reporter';
export const buyQuoteUpdater = {
updateBuyQuoteAsync: async (
@@ -16,7 +18,12 @@ export const buyQuoteUpdater = {
dispatch: Dispatch<Action>,
asset: ERC20Asset,
assetUnitAmount: BigNumber,
- options: { setPending: boolean; dispatchErrors: boolean; affiliateInfo?: AffiliateInfo },
+ fetchOrigin: QuoteFetchOrigin,
+ options: {
+ setPending: boolean;
+ dispatchErrors: boolean;
+ affiliateInfo?: AffiliateInfo;
+ },
): Promise<void> => {
// get a new buy quote.
const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetUnitAmount, asset.metaData.decimals);
@@ -29,34 +36,24 @@ export const buyQuoteUpdater = {
try {
newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
} catch (error) {
+ const errorMessage = assetUtils.assetBuyerErrorMessage(asset, error);
+
+ if (_.isUndefined(errorMessage)) {
+ // This is an unknown error, report it to rollbar
+ errorReporter.report(error);
+ }
+
if (options.dispatchErrors) {
dispatch(actions.setQuoteRequestStateFailure());
- let errorMessage;
- if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
- const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
- errorMessage = `Not enough ${assetName} available`;
- } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
- errorMessage = 'Not enough ZRX available';
- } else if (
- error.message === AssetBuyerError.StandardRelayerApiError ||
- error.message.startsWith(AssetBuyerError.AssetUnavailable)
- ) {
- const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
- errorMessage = `${assetName} is currently unavailable`;
- }
- if (!_.isUndefined(errorMessage)) {
- errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
- } else {
- throw error;
- }
+ analytics.trackQuoteError(error.message ? error.message : 'other', baseUnitValue, fetchOrigin);
+ errorFlasher.flashNewErrorMessage(dispatch, errorMessage || 'Error fetching price, please try again');
}
- // TODO: report to error reporter on else
-
return;
}
// We have a successful new buy quote
errorFlasher.clearError(dispatch);
// invalidate the last buy quote.
dispatch(actions.updateLatestBuyQuote(newBuyQuote));
+ analytics.trackQuoteFetched(newBuyQuote, fetchOrigin);
},
};
diff --git a/packages/instant/src/util/error_reporter.ts b/packages/instant/src/util/error_reporter.ts
new file mode 100644
index 000000000..b1824eaf9
--- /dev/null
+++ b/packages/instant/src/util/error_reporter.ts
@@ -0,0 +1,62 @@
+import { logUtils } from '@0x/utils';
+import * as _ from 'lodash';
+
+import { GIT_SHA, HOST_DOMAINS, INSTANT_DISCHARGE_TARGET, ROLLBAR_CLIENT_TOKEN, ROLLBAR_ENABLED } from '../constants';
+
+// Import version of Rollbar designed for embedded components
+// See https://docs.rollbar.com/docs/using-rollbarjs-inside-an-embedded-component
+// tslint:disable-next-line:no-var-requires
+const Rollbar = require('rollbar/dist/rollbar.noconflict.umd');
+
+let rollbar: any;
+// Configures rollbar and sets up error catching
+export const setupRollbar = (): any => {
+ if (_.isUndefined(rollbar) && ROLLBAR_CLIENT_TOKEN && ROLLBAR_ENABLED) {
+ rollbar = new Rollbar({
+ accessToken: ROLLBAR_CLIENT_TOKEN,
+ captureUncaught: true,
+ captureUnhandledRejections: true,
+ enabled: true,
+ itemsPerMinute: 10,
+ maxItems: 500,
+ payload: {
+ environment: INSTANT_DISCHARGE_TARGET || `Local ${process.env.NODE_ENV}`,
+ client: {
+ javascript: {
+ source_map_enabled: true,
+ code_version: GIT_SHA,
+ guess_uncaught_frames: true,
+ },
+ },
+ },
+ hostWhiteList: HOST_DOMAINS,
+ uncaughtErrorLevel: 'error',
+ ignoredMessages: [
+ // Errors from the third-party scripts
+ 'Script error',
+ // Network errors or ad-blockers
+ 'TypeError: Failed to fetch',
+ 'Exchange has not been deployed to detected network (network/artifact mismatch)',
+ // Source: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/7VU0_VvC7mE
+ "undefined is not an object (evaluating '__gCrWeb.autofill.extractForms')",
+ // Source: http://stackoverflow.com/questions/43399818/securityerror-from-facebook-and-cross-domain-messaging
+ 'SecurityError (DOM Exception 18)',
+ ],
+ });
+ }
+};
+
+export const errorReporter = {
+ report(err: Error): void {
+ if (!rollbar) {
+ logUtils.log('Not reporting to rollbar because not configured', err);
+ return;
+ }
+
+ rollbar.error(err, (rollbarErr: Error) => {
+ if (rollbarErr) {
+ logUtils.log(`Error reporting to rollbar, ignoring: ${rollbarErr}`);
+ }
+ });
+ },
+};
diff --git a/packages/instant/src/util/gas_price_estimator.ts b/packages/instant/src/util/gas_price_estimator.ts
index 6b15809a3..332c8d00a 100644
--- a/packages/instant/src/util/gas_price_estimator.ts
+++ b/packages/instant/src/util/gas_price_estimator.ts
@@ -7,6 +7,8 @@ import {
GWEI_IN_WEI,
} from '../constants';
+import { errorReporter } from './error_reporter';
+
interface EthGasStationResult {
average: number;
fastestWait: number;
@@ -42,8 +44,9 @@ export class GasPriceEstimator {
let fetchedAmount: GasInfo | undefined;
try {
fetchedAmount = await fetchFastAmountInWeiAsync();
- } catch {
+ } catch (e) {
fetchedAmount = undefined;
+ errorReporter.report(e);
}
if (fetchedAmount) {
diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts
index 7c53c9918..279ff3059 100644
--- a/packages/instant/src/util/heap.ts
+++ b/packages/instant/src/util/heap.ts
@@ -5,6 +5,7 @@ import * as _ from 'lodash';
import { HEAP_ANALYTICS_ID } from '../constants';
import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics';
+import { errorReporter } from './error_reporter';
export type EventProperties = ObjectMap<string | number>;
@@ -107,8 +108,8 @@ export const heapUtil = {
heapFunctionCall(curHeap);
} catch (e) {
// We never want analytics to crash our React component
- // TODO(sk): error reporter here
logUtils.log('Analytics error', e);
+ errorReporter.report(e);
}
}
},
diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts
index 2b852fb0d..cf29bf3ea 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 { QuoteFetchOrigin } from '../types';
import { Heartbeater } from './heartbeater';
@@ -17,8 +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,
- });
+ await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(
+ store.getState(),
+ store.dispatch,
+ QuoteFetchOrigin.Heartbeat,
+ {
+ updateSilently: true,
+ },
+ );
}, shouldPerformImmediatelyOnStart);
};
diff --git a/packages/instant/test/util/asset.test.ts b/packages/instant/test/util/asset.test.ts
index 4229b24ed..fc4e4e2e4 100644
--- a/packages/instant/test/util/asset.test.ts
+++ b/packages/instant/test/util/asset.test.ts
@@ -1,6 +1,7 @@
+import { AssetBuyerError } from '@0x/asset-buyer';
import { AssetProxyId, ObjectMap } from '@0x/types';
-import { Asset, AssetMetaData, ERC20AssetMetaData, Network, ZeroExInstantError } from '../../src/types';
+import { Asset, AssetMetaData, ERC20Asset, ERC20AssetMetaData, Network, ZeroExInstantError } from '../../src/types';
import { assetUtils } from '../../src/util/asset';
const ZRX_ASSET_DATA = '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
@@ -11,7 +12,7 @@ const ZRX_META_DATA: ERC20AssetMetaData = {
decimals: 18,
name: '0x',
};
-const ZRX_ASSET: Asset = {
+const ZRX_ASSET: ERC20Asset = {
assetData: ZRX_ASSET_DATA,
metaData: ZRX_META_DATA,
};
@@ -45,4 +46,32 @@ describe('assetDataUtil', () => {
).toThrowError(ZeroExInstantError.AssetMetaDataNotAvailable);
});
});
+ describe('assetBuyerErrorMessage', () => {
+ it('should return message for InsufficientAssetLiquidity', () => {
+ const insufficientAssetError = new Error(AssetBuyerError.InsufficientAssetLiquidity);
+ expect(assetUtils.assetBuyerErrorMessage(ZRX_ASSET, insufficientAssetError)).toEqual(
+ 'Not enough ZRX available',
+ );
+ });
+ it('should return message for InsufficientAssetLiquidity', () => {
+ const insufficientZrxError = new Error(AssetBuyerError.InsufficientZrxLiquidity);
+ expect(assetUtils.assetBuyerErrorMessage(ZRX_ASSET, insufficientZrxError)).toEqual(
+ 'Not enough ZRX available',
+ );
+ });
+ it('should message for StandardRelayerApiError', () => {
+ const standardRelayerError = new Error(AssetBuyerError.StandardRelayerApiError);
+ expect(assetUtils.assetBuyerErrorMessage(ZRX_ASSET, standardRelayerError)).toEqual(
+ 'ZRX is currently unavailable',
+ );
+ });
+ it('should return error for AssetUnavailable error', () => {
+ const assetUnavailableError = new Error(
+ `${AssetBuyerError.AssetUnavailable}: For assetData ${ZRX_ASSET_DATA}`,
+ );
+ expect(assetUtils.assetBuyerErrorMessage(ZRX_ASSET, assetUnavailableError)).toEqual(
+ 'ZRX is currently unavailable',
+ );
+ });
+ });
});
diff --git a/packages/instant/tsconfig.json b/packages/instant/tsconfig.json
index 14b0ad8f7..2b3c11c9f 100644
--- a/packages/instant/tsconfig.json
+++ b/packages/instant/tsconfig.json
@@ -5,8 +5,10 @@
"rootDir": "src",
"jsx": "react",
"noImplicitAny": true,
- "allowSyntheticDefaultImports": true
+ "allowSyntheticDefaultImports": true,
+ "declaration": false,
+ "declarationMap": false,
+ "composite": false
},
- "include": ["./src/**/*"],
- "exclude": ["./src/index.umd.ts"]
+ "include": ["./src/**/*"]
}
diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js
index 41276809c..e74cf36d9 100644
--- a/packages/instant/webpack.config.js
+++ b/packages/instant/webpack.config.js
@@ -1,32 +1,119 @@
const childProcess = require('child_process');
const ip = require('ip');
const path = require('path');
+const RollbarSourceMapPlugin = require('rollbar-sourcemap-webpack-plugin');
const webpack = require('webpack');
-// The common js bundle (not this one) is built using tsc.
-// The umd bundle (this one) has a different entrypoint.
-
const GIT_SHA = childProcess
.execSync('git rev-parse HEAD')
.toString()
.trim();
-const HEAP_PRODUCTION_ENV_VAR_NAME = 'INSTANT_HEAP_ANALYTICS_ID_PRODUCTION';
-const HEAP_DEVELOPMENT_ENV_VAR_NAME = 'INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT';
-const getHeapAnalyticsId = modeName => {
- if (modeName === 'production') {
- return process.env[HEAP_PRODUCTION_ENV_VAR_NAME];
+const DISCHARGE_TARGETS_THAT_REQUIRED_HEAP = ['production', 'staging', 'dogfood'];
+const getHeapConfigForDischargeTarget = dischargeTarget => {
+ return {
+ heapAnalyticsIdEnvName:
+ dischargeTarget === 'production'
+ ? 'INSTANT_HEAP_ANALYTICS_ID_PRODUCTION'
+ : 'INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT',
+ heapAnalyticsIdRequired: DISCHARGE_TARGETS_THAT_REQUIRED_HEAP.includes(dischargeTarget),
+ };
+};
+
+const DISCHARGE_TARGETS_THAT_REQUIRE_ROLLBAR = ['production', 'staging', 'dogfood'];
+const getRollbarConfigForDischargeTarget = dischargeTarget => {
+ if (DISCHARGE_TARGETS_THAT_REQUIRE_ROLLBAR.includes(dischargeTarget)) {
+ const rollbarSourceMapPublicPath =
+ dischargeTarget === 'production'
+ ? 'https://instant.0xproject.com'
+ : `http://0x-instant-${dischargeTarget}.s3-website-us-east-1.amazonaws.com`;
+
+ return {
+ rollbarSourceMapPublicPath,
+ rollbarRequired: true,
+ };
}
- if (modeName === 'development') {
- return process.env[HEAP_DEVELOPMENT_ENV_VAR_NAME];
+ return {
+ rollbarRequired: false,
+ };
+};
+
+const ROLLBAR_CLIENT_TOKEN_ENV_VAR_NAME = 'INSTANT_ROLLBAR_CLIENT_TOKEN';
+const ROLLBAR_PUBLISH_TOKEN_ENV_VAR_NAME = 'INSTANT_ROLLBAR_PUBLISH_TOKEN';
+const getRollbarTokens = (dischargeTarget, rollbarRequired) => {
+ const clientToken = process.env[ROLLBAR_CLIENT_TOKEN_ENV_VAR_NAME];
+ const publishToken = process.env[ROLLBAR_PUBLISH_TOKEN_ENV_VAR_NAME];
+
+ if (rollbarRequired) {
+ if (!clientToken) {
+ throw new Error(
+ `Rollbar client token required for ${dischargeTarget}, please set env var ${ROLLBAR_CLIENT_TOKEN_ENV_VAR_NAME}`,
+ );
+ }
+ if (!publishToken) {
+ throw new Error(
+ `Rollbar publish token required for ${dischargeTarget}, please set env var ${ROLLBAR_PUBLISH_TOKEN_ENV_VAR_NAME}`,
+ );
+ }
}
- return undefined;
+ return { clientToken, publishToken };
};
-module.exports = (env, argv) => {
+const generateConfig = (dischargeTarget, heapConfigOptions, rollbarConfigOptions, nodeEnv) => {
const outputPath = process.env.WEBPACK_OUTPUT_PATH || 'umd';
+
+ const { heapAnalyticsIdEnvName, heapAnalyticsIdRequired } = heapConfigOptions;
+ const heapAnalyticsId = process.env[heapAnalyticsIdEnvName];
+ if (heapAnalyticsIdRequired && !heapAnalyticsId) {
+ throw new Error(
+ `Must define heap analytics id in ENV var ${heapAnalyticsIdEnvName} when building for ${dischargeTarget}`,
+ );
+ }
+ const heapEnabled = heapAnalyticsId && (nodeEnv !== 'development' || process.env.INSTANT_HEAP_FORCE_DEVELOPMENT);
+
+ const rollbarTokens = getRollbarTokens(dischargeTarget, rollbarConfigOptions.rollbarRequired);
+ const rollbarEnabled =
+ rollbarTokens.clientToken && (nodeEnv !== 'development' || process.env.INSTANT_ROLLBAR_FORCE_DEVELOPMENT);
+
+ let rollbarPlugin;
+ if (rollbarConfigOptions.rollbarRequired) {
+ if (!rollbarEnabled || !rollbarTokens.publishToken || !rollbarConfigOptions.rollbarSourceMapPublicPath) {
+ throw new Error(`Rollbar required for ${dischargeTarget} but not configured`);
+ }
+ rollbarPlugin = new RollbarSourceMapPlugin({
+ accessToken: rollbarTokens.publishToken,
+ version: GIT_SHA,
+ publicPath: rollbarConfigOptions.rollbarSourceMapPublicPath,
+ });
+ }
+
+ const envVars = {
+ GIT_SHA: JSON.stringify(GIT_SHA),
+ NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version),
+ ROLLBAR_ENABLED: rollbarEnabled,
+ HEAP_ENABLED: heapEnabled
+ };
+ if (dischargeTarget) {
+ envVars.INSTANT_DISCHARGE_TARGET = JSON.stringify(dischargeTarget);
+ }
+ if (heapAnalyticsId) {
+ envVars.HEAP_ANALYTICS_ID = JSON.stringify(heapAnalyticsId);
+ }
+ if (rollbarTokens.clientToken) {
+ envVars.ROLLBAR_CLIENT_TOKEN = JSON.stringify(rollbarTokens.clientToken);
+ }
+
+ const plugins = [
+ new webpack.DefinePlugin({
+ 'process.env': envVars,
+ }),
+ ];
+ if (rollbarPlugin) {
+ plugins.push(rollbarPlugin);
+ }
+
const config = {
entry: {
instant: './src/index.umd.ts',
@@ -37,15 +124,7 @@ module.exports = (env, argv) => {
library: 'zeroExInstant',
libraryTarget: 'umd',
},
- plugins: [
- new webpack.DefinePlugin({
- 'process.env': {
- GIT_SHA: JSON.stringify(GIT_SHA),
- HEAP_ANALYTICS_ID: getHeapAnalyticsId(argv.mode),
- NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version),
- },
- }),
- ],
+ plugins,
devtool: 'source-map',
resolve: {
extensions: ['.js', '.json', '.ts', '.tsx'],
@@ -60,6 +139,15 @@ module.exports = (env, argv) => {
test: /\.svg$/,
loader: 'svg-react-loader',
},
+ {
+ test: /\.js$/,
+ loader: 'source-map-loader',
+ exclude: [
+ // instead of /\/node_modules\//
+ path.join(process.cwd(), 'node_modules'),
+ path.join(process.cwd(), '../..', 'node_modules'),
+ ],
+ },
],
},
devServer: {
@@ -79,3 +167,10 @@ module.exports = (env, argv) => {
};
return config;
};
+
+module.exports = (env, argv) => {
+ const dischargeTarget = env ? env.discharge_target : undefined;
+ const heapConfigOptions = getHeapConfigForDischargeTarget(dischargeTarget);
+ const rollbarConfigOptions = getRollbarConfigForDischargeTarget(dischargeTarget);
+ return generateConfig(dischargeTarget, heapConfigOptions, rollbarConfigOptions, argv.mode);
+};
diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json
index 332fbb466..7622fa5d4 100644
--- a/packages/metacoin/package.json
+++ b/packages/metacoin/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/metacoin",
- "version": "0.0.29",
+ "version": "0.0.30",
"engines": {
"node": ">=6.12"
},
@@ -30,15 +30,15 @@
"license": "Apache-2.0",
"dependencies": {
"@0x/abi-gen": "^1.0.17",
- "@0x/abi-gen-templates": "^1.0.0",
- "@0x/base-contract": "^3.0.7",
- "@0x/sol-cov": "^2.1.13",
- "@0x/subproviders": "^2.1.5",
+ "@0x/abi-gen-templates": "^1.0.1",
+ "@0x/base-contract": "^3.0.8",
+ "@0x/sol-cov": "^2.1.14",
+ "@0x/subproviders": "^2.1.6",
"@0x/tslint-config": "^1.0.10",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@types/mocha": "^5.2.2",
"copyfiles": "^2.0.0",
"ethereum-types": "^1.1.2",
@@ -47,8 +47,8 @@
"run-s": "^0.0.0"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
- "@0x/sol-compiler": "^1.1.13",
+ "@0x/dev-utils": "^1.0.19",
+ "@0x/sol-compiler": "^1.1.14",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json
index 07031fc09..56705fc1a 100644
--- a/packages/migrations/CHANGELOG.json
+++ b/packages/migrations/CHANGELOG.json
@@ -14,7 +14,8 @@
"note": "Fund the Forwarder with ZRX for fees.",
"pr": 1309
}
- ]
+ ],
+ "timestamp": 1543401373
},
{
"version": "2.1.0",
diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md
index 986e224b0..3808b2d3d 100644
--- a/packages/migrations/CHANGELOG.md
+++ b/packages/migrations/CHANGELOG.md
@@ -5,6 +5,12 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.2.0 - _November 28, 2018_
+
+ * Add CLI `0x-migrate` for running the 0x migrations in a language-agnostic way (#1324)
+ * Deploy testnet Exchange arfitact. Previously mainnet Exchange artifact was deployed. (#1309)
+ * Fund the Forwarder with ZRX for fees. (#1309)
+
## v2.1.0 - _November 21, 2018_
* Export all type declarations used by the public interface, as well as the `ContractAddresses` mapping (#1301)
diff --git a/packages/migrations/package.json b/packages/migrations/package.json
index b006a470a..f4dd1f9f9 100644
--- a/packages/migrations/package.json
+++ b/packages/migrations/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/migrations",
- "version": "2.1.0",
+ "version": "2.2.0",
"engines": {
"node": ">=6.12"
},
@@ -26,7 +26,7 @@
},
"license": "Apache-2.0",
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
+ "@0x/dev-utils": "^1.0.19",
"@0x/tslint-config": "^1.0.10",
"@0x/types": "^1.3.0",
"@types/yargs": "^10.0.0",
@@ -39,16 +39,16 @@
"yargs": "^10.0.3"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.1.0",
- "@0x/base-contract": "^3.0.7",
- "@0x/contract-addresses": "^1.2.0",
- "@0x/contract-artifacts": "^1.1.0",
- "@0x/order-utils": "^3.0.3",
- "@0x/sol-compiler": "^1.1.13",
- "@0x/subproviders": "^2.1.5",
+ "@0x/abi-gen-wrappers": "^2.0.0",
+ "@0x/base-contract": "^3.0.8",
+ "@0x/contract-addresses": "^2.0.0",
+ "@0x/contract-artifacts": "^1.1.2",
+ "@0x/order-utils": "^3.0.4",
+ "@0x/sol-compiler": "^1.1.14",
+ "@0x/subproviders": "^2.1.6",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@ledgerhq/hw-app-eth": "^4.3.0",
"ethereum-types": "^1.1.2",
"ethers": "~4.0.4",
diff --git a/packages/monorepo-scripts/CHANGELOG.json b/packages/monorepo-scripts/CHANGELOG.json
index 170a97a33..428168437 100644
--- a/packages/monorepo-scripts/CHANGELOG.json
+++ b/packages/monorepo-scripts/CHANGELOG.json
@@ -13,6 +13,10 @@
{
"note": "Add ForwarderError to the IGNORED_EXCESSIVE_TYPES array",
"pr": 1147
+ },
+ {
+ "note": "Fix a bug when hardcoded CHANGELOG paths cause fetching release notes to fail",
+ "pr": 1311
}
]
},
diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts
index 60cdccf1d..36e61714b 100644
--- a/packages/monorepo-scripts/src/prepublish_checks.ts
+++ b/packages/monorepo-scripts/src/prepublish_checks.ts
@@ -17,7 +17,6 @@ async function prepublishChecksAsync(): Promise<void> {
await checkChangelogFormatAsync(updatedPublicPackages);
await checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicPackages);
await checkPublishRequiredSetupAsync();
- checkRequiredEnvVariables();
}
async function checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicPackages: Package[]): Promise<void> {
@@ -184,16 +183,6 @@ async function checkPublishRequiredSetupAsync(): Promise<void> {
}
}
-const checkRequiredEnvVariables = () => {
- utils.log('Checking required environment variables...');
- const requiredEnvVars = ['INSTANT_HEAP_ANALYTICS_ID_PRODUCTION'];
- requiredEnvVars.forEach(requiredEnvVarName => {
- if (_.isUndefined(process.env[requiredEnvVarName])) {
- throw new Error(`Must have ${requiredEnvVarName} set`);
- }
- });
-};
-
prepublishChecksAsync().catch(err => {
utils.log(err);
process.exit(1);
diff --git a/packages/monorepo-scripts/src/utils/github_release_utils.ts b/packages/monorepo-scripts/src/utils/github_release_utils.ts
index 7434d397e..e63244b46 100644
--- a/packages/monorepo-scripts/src/utils/github_release_utils.ts
+++ b/packages/monorepo-scripts/src/utils/github_release_utils.ts
@@ -41,7 +41,7 @@ export async function publishReleaseNotesAsync(packagesToPublish: Package[], isD
let assets: string[] = [];
let aggregateNotes = '';
_.each(packagesToPublish, pkg => {
- aggregateNotes += getReleaseNotesForPackage(pkg.packageJson.name);
+ aggregateNotes += getReleaseNotesForPackage(pkg.location, pkg.packageJson.name);
const packageAssets = _.get(pkg.packageJson, 'config.postpublish.assets');
if (!_.isUndefined(packageAssets)) {
@@ -88,14 +88,8 @@ function adjustAssetPaths(assets: string[]): string[] {
return finalAssets;
}
-function getReleaseNotesForPackage(packageName: string): string {
- const packageNameWithoutNamespace = packageName.replace('@0x/', '');
- const changelogJSONPath = path.join(
- constants.monorepoRootPath,
- 'packages',
- packageNameWithoutNamespace,
- 'CHANGELOG.json',
- );
+function getReleaseNotesForPackage(packageLocation: string, packageName: string): string {
+ const changelogJSONPath = path.join(packageLocation, 'CHANGELOG.json');
const changelogJSON = readFileSync(changelogJSONPath, 'utf-8');
const changelogs = JSON.parse(changelogJSON);
const latestLog = changelogs[0];
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json
index a4f5dc622..6c8fd6239 100644
--- a/packages/order-utils/CHANGELOG.json
+++ b/packages/order-utils/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "3.0.4",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "3.0.3",
"changes": [
diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md
index b863cbc03..5eae590b5 100644
--- a/packages/order-utils/CHANGELOG.md
+++ b/packages/order-utils/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.0.4 - _November 28, 2018_
+
+ * Dependencies updated
+
## v3.0.3 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json
index e032d6e7d..50229dafb 100644
--- a/packages/order-utils/package.json
+++ b/packages/order-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/order-utils",
- "version": "3.0.3",
+ "version": "3.0.4",
"engines": {
"node": ">=6.12"
},
@@ -35,7 +35,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md",
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
+ "@0x/dev-utils": "^1.0.19",
"@0x/tslint-config": "^1.0.10",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
@@ -53,15 +53,15 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.1.0",
+ "@0x/abi-gen-wrappers": "^2.0.0",
"@0x/assert": "^1.0.18",
- "@0x/base-contract": "^3.0.7",
- "@0x/contract-artifacts": "^1.1.0",
+ "@0x/base-contract": "^3.0.8",
+ "@0x/contract-artifacts": "^1.1.2",
"@0x/json-schemas": "^2.1.2",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@types/node": "*",
"bn.js": "^4.11.8",
"ethereum-types": "^1.1.2",
diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json
index ca2de9831..4e56dc400 100644
--- a/packages/order-watcher/CHANGELOG.json
+++ b/packages/order-watcher/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "2.2.6",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "2.2.5",
"changes": [
diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md
index 7ae47fdda..37b4a7438 100644
--- a/packages/order-watcher/CHANGELOG.md
+++ b/packages/order-watcher/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.2.6 - _November 28, 2018_
+
+ * Dependencies updated
+
## v2.2.5 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json
index 4257bd2a8..9a51203f4 100644
--- a/packages/order-watcher/package.json
+++ b/packages/order-watcher/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/order-watcher",
- "version": "2.2.5",
+ "version": "2.2.6",
"description": "An order watcher daemon that watches for order validity",
"keywords": [
"0x",
@@ -33,8 +33,8 @@
"node": ">=6.0.0"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
- "@0x/migrations": "^2.1.0",
+ "@0x/dev-utils": "^1.0.19",
+ "@0x/migrations": "^2.2.0",
"@0x/tslint-config": "^1.0.10",
"@types/bintrees": "^1.0.2",
"@types/lodash": "4.14.104",
@@ -57,19 +57,19 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/abi-gen-wrappers": "^1.1.0",
+ "@0x/abi-gen-wrappers": "^2.0.0",
"@0x/assert": "^1.0.18",
- "@0x/base-contract": "^3.0.7",
- "@0x/contract-addresses": "^1.2.0",
- "@0x/contract-artifacts": "^1.1.0",
- "@0x/contract-wrappers": "^4.1.0",
- "@0x/fill-scenarios": "^1.0.13",
+ "@0x/base-contract": "^3.0.8",
+ "@0x/contract-addresses": "^2.0.0",
+ "@0x/contract-artifacts": "^1.1.2",
+ "@0x/contract-wrappers": "^4.1.1",
+ "@0x/fill-scenarios": "^1.0.14",
"@0x/json-schemas": "^2.1.2",
- "@0x/order-utils": "^3.0.3",
+ "@0x/order-utils": "^3.0.4",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"bintrees": "^1.0.2",
"ethereum-types": "^1.1.2",
"ethereumjs-blockstream": "6.0.0",
diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json
index cecc270eb..d456a3b53 100644
--- a/packages/react-docs/CHANGELOG.json
+++ b/packages/react-docs/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "1.0.20",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.0.19",
"changes": [
diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md
index f0a56191d..e48f43fb8 100644
--- a/packages/react-docs/CHANGELOG.md
+++ b/packages/react-docs/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.20 - _November 28, 2018_
+
+ * Dependencies updated
+
## v1.0.19 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json
index 6e819ee72..968ac4e34 100644
--- a/packages/react-docs/package.json
+++ b/packages/react-docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/react-docs",
- "version": "1.0.19",
+ "version": "1.0.20",
"engines": {
"node": ">=6.12"
},
@@ -24,7 +24,7 @@
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
+ "@0x/dev-utils": "^1.0.19",
"@0x/tslint-config": "^1.0.10",
"@types/compare-versions": "^3.0.0",
"@types/styled-components": "^4.0.0",
@@ -34,7 +34,7 @@
"typescript": "3.0.1"
},
"dependencies": {
- "@0x/react-shared": "^1.0.22",
+ "@0x/react-shared": "^1.0.23",
"@0x/types": "^1.3.0",
"@0x/utils": "^2.0.6",
"@types/lodash": "4.14.104",
diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json
index bcbf2d9f9..a376bae29 100644
--- a/packages/react-shared/CHANGELOG.json
+++ b/packages/react-shared/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "1.0.23",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.0.22",
"changes": [
diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md
index c6fb9e479..a983e0af2 100644
--- a/packages/react-shared/CHANGELOG.md
+++ b/packages/react-shared/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.23 - _November 28, 2018_
+
+ * Dependencies updated
+
## v1.0.22 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json
index 34412e14e..b5816ad98 100644
--- a/packages/react-shared/package.json
+++ b/packages/react-shared/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/react-shared",
- "version": "1.0.22",
+ "version": "1.0.23",
"engines": {
"node": ">=6.12"
},
@@ -25,7 +25,7 @@
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
+ "@0x/dev-utils": "^1.0.19",
"@0x/tslint-config": "^1.0.10",
"make-promises-safe": "^1.1.0",
"shx": "^0.2.2",
diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json
index 2ca983c59..fe077b6cc 100644
--- a/packages/sol-compiler/CHANGELOG.json
+++ b/packages/sol-compiler/CHANGELOG.json
@@ -1,5 +1,23 @@
[
{
+ "version": "1.1.15",
+ "changes": [
+ {
+ "note": "Fix bug where we were appending base path to absolute imports (e.g NPM imports)",
+ "pr": 1311
+ }
+ ]
+ },
+ {
+ "timestamp": 1543401373,
+ "version": "1.1.14",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.1.13",
"changes": [
diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md
index e535df64e..a1782bb3b 100644
--- a/packages/sol-compiler/CHANGELOG.md
+++ b/packages/sol-compiler/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.1.14 - _November 28, 2018_
+
+ * Dependencies updated
+
## v1.1.13 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json
index bcc235866..d27c0ee31 100644
--- a/packages/sol-compiler/package.json
+++ b/packages/sol-compiler/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-compiler",
- "version": "1.1.13",
+ "version": "1.1.14",
"engines": {
"node": ">=6.12"
},
@@ -42,7 +42,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md",
"devDependencies": {
- "@0x/dev-utils": "^1.0.18",
+ "@0x/dev-utils": "^1.0.19",
"@0x/tslint-config": "^1.0.10",
"@types/mkdirp": "^0.5.2",
"@types/require-from-string": "^1.2.0",
@@ -71,7 +71,7 @@
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@types/yargs": "^11.0.0",
"chalk": "^2.3.0",
"ethereum-types": "^1.1.2",
diff --git a/packages/sol-compiler/src/compiler.ts b/packages/sol-compiler/src/compiler.ts
index 8ee7fa4a9..cba67f292 100644
--- a/packages/sol-compiler/src/compiler.ts
+++ b/packages/sol-compiler/src/compiler.ts
@@ -394,7 +394,14 @@ export class Compiler {
//
const lastPathSeparatorPos = contractPath.lastIndexOf('/');
const contractFolder = lastPathSeparatorPos === -1 ? '' : contractPath.slice(0, lastPathSeparatorPos + 1);
- importPath = path.resolve('/' + contractFolder, importPath).replace('/', '');
+ if (importPath.startsWith('.')) {
+ /**
+ * Some imports path are relative ("../Token.sol", "./Wallet.sol")
+ * while others are absolute ("Token.sol", "@0x/contracts/Wallet.sol")
+ * And we need to append the base path for relative imports.
+ */
+ importPath = path.resolve('/' + contractFolder, importPath).replace('/', '');
+ }
if (_.isUndefined(sourcesToAppendTo[importPath])) {
sourcesToAppendTo[importPath] = { id: fullSources[importPath].id };
diff --git a/packages/sol-cov/CHANGELOG.json b/packages/sol-cov/CHANGELOG.json
index 3dd04be8c..bc8aa71e1 100644
--- a/packages/sol-cov/CHANGELOG.json
+++ b/packages/sol-cov/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "2.1.14",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "2.1.13",
"changes": [
diff --git a/packages/sol-cov/CHANGELOG.md b/packages/sol-cov/CHANGELOG.md
index e56a1393e..25ba93026 100644
--- a/packages/sol-cov/CHANGELOG.md
+++ b/packages/sol-cov/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.1.14 - _November 28, 2018_
+
+ * Dependencies updated
+
## v2.1.13 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index 9dcb3b854..73c11980f 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-cov",
- "version": "2.1.13",
+ "version": "2.1.14",
"engines": {
"node": ">=6.12"
},
@@ -42,12 +42,12 @@
},
"homepage": "https://github.com/0xProject/0x.js/packages/sol-cov/README.md",
"dependencies": {
- "@0x/dev-utils": "^1.0.18",
- "@0x/sol-compiler": "^1.1.13",
- "@0x/subproviders": "^2.1.5",
+ "@0x/dev-utils": "^1.0.19",
+ "@0x/sol-compiler": "^1.1.14",
+ "@0x/subproviders": "^2.1.6",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@types/solidity-parser-antlr": "^0.2.0",
"ethereum-types": "^1.1.2",
"ethereumjs-util": "^5.1.1",
diff --git a/packages/sol-doc/CHANGELOG.json b/packages/sol-doc/CHANGELOG.json
index c3dcc81f1..332aeb025 100644
--- a/packages/sol-doc/CHANGELOG.json
+++ b/packages/sol-doc/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "1.0.9",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.0.8",
"changes": [
diff --git a/packages/sol-doc/CHANGELOG.md b/packages/sol-doc/CHANGELOG.md
index a7a7fa0fa..5a1df59c7 100644
--- a/packages/sol-doc/CHANGELOG.md
+++ b/packages/sol-doc/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.9 - _November 28, 2018_
+
+ * Dependencies updated
+
## v1.0.8 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/sol-doc/package.json b/packages/sol-doc/package.json
index 6bf76d47a..edf1707d6 100644
--- a/packages/sol-doc/package.json
+++ b/packages/sol-doc/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/sol-doc",
- "version": "1.0.8",
+ "version": "1.0.9",
"description": "Solidity documentation generator",
"main": "lib/src/index.js",
"types": "lib/src/index.d.js",
@@ -25,7 +25,7 @@
"author": "F. Eugene Aumson",
"license": "Apache-2.0",
"dependencies": {
- "@0x/sol-compiler": "^1.1.13",
+ "@0x/sol-compiler": "^1.1.14",
"@0x/types": "^1.3.0",
"@0x/utils": "^2.0.6",
"ethereum-types": "^1.1.2",
diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json
index fdfb4009b..4c9e612d7 100644
--- a/packages/sol-resolver/CHANGELOG.json
+++ b/packages/sol-resolver/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "version": "1.1.0",
+ "changes": [
+ {
+ "note": "NPMResolver now supports scoped packages",
+ "pr": 1311
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "1.0.17",
"changes": [
diff --git a/packages/sol-resolver/src/resolvers/npm_resolver.ts b/packages/sol-resolver/src/resolvers/npm_resolver.ts
index a2df0dcad..eeb2b5493 100644
--- a/packages/sol-resolver/src/resolvers/npm_resolver.ts
+++ b/packages/sol-resolver/src/resolvers/npm_resolver.ts
@@ -1,4 +1,5 @@
import * as fs from 'fs';
+import * as _ from 'lodash';
import * as path from 'path';
import { ContractSource } from '../types';
@@ -13,12 +14,22 @@ export class NPMResolver extends Resolver {
}
public resolveIfExists(importPath: string): ContractSource | undefined {
if (!importPath.startsWith('/')) {
- const [packageName, ...other] = importPath.split('/');
+ let packageName;
+ let packageScopeIfExists;
+ let other;
+ if (_.startsWith(importPath, '@')) {
+ [packageScopeIfExists, packageName, ...other] = importPath.split('/');
+ } else {
+ [packageName, ...other] = importPath.split('/');
+ }
const pathWithinPackage = path.join(...other);
let currentPath = this._packagePath;
const ROOT_PATH = '/';
while (currentPath !== ROOT_PATH) {
- const lookupPath = path.join(currentPath, 'node_modules', packageName, pathWithinPackage);
+ const packagePath = _.isUndefined(packageScopeIfExists)
+ ? packageName
+ : path.join(packageScopeIfExists, packageName);
+ const lookupPath = path.join(currentPath, 'node_modules', packagePath, pathWithinPackage);
if (fs.existsSync(lookupPath) && fs.lstatSync(lookupPath).isFile()) {
const fileContent = fs.readFileSync(lookupPath).toString();
return {
diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json
index 62c495b49..6da170be3 100644
--- a/packages/subproviders/CHANGELOG.json
+++ b/packages/subproviders/CHANGELOG.json
@@ -1,5 +1,14 @@
[
{
+ "timestamp": 1543401373,
+ "version": "2.1.6",
+ "changes": [
+ {
+ "note": "Dependencies updated"
+ }
+ ]
+ },
+ {
"timestamp": 1542821676,
"version": "2.1.5",
"changes": [
diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md
index 0251b6d9a..01dd8d652 100644
--- a/packages/subproviders/CHANGELOG.md
+++ b/packages/subproviders/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v2.1.6 - _November 28, 2018_
+
+ * Dependencies updated
+
## v2.1.5 - _November 21, 2018_
* Dependencies updated
diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json
index 3b367054b..86f3738af 100644
--- a/packages/subproviders/package.json
+++ b/packages/subproviders/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/subproviders",
- "version": "2.1.5",
+ "version": "2.1.6",
"engines": {
"node": ">=6.12"
},
@@ -33,7 +33,7 @@
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"@ledgerhq/hw-app-eth": "^4.3.0",
"@ledgerhq/hw-transport-u2f": "4.24.0",
"@types/eth-lightwallet": "^3.0.0",
diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json
index cdfd1b7ff..8c4b942a3 100644
--- a/packages/testnet-faucets/package.json
+++ b/packages/testnet-faucets/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@0x/testnet-faucets",
- "version": "1.0.57",
+ "version": "1.0.58",
"engines": {
"node": ">=6.12"
},
@@ -18,11 +18,11 @@
"author": "Fabio Berger",
"license": "Apache-2.0",
"dependencies": {
- "0x.js": "^2.0.5",
- "@0x/subproviders": "^2.1.5",
+ "0x.js": "^2.0.6",
+ "@0x/subproviders": "^2.1.6",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
+ "@0x/web3-wrapper": "^3.1.6",
"body-parser": "^1.17.1",
"ethereum-types": "^1.1.2",
"ethereumjs-tx": "^1.3.5",
diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json
index 0b32b60f0..b09859101 100644
--- a/packages/types/CHANGELOG.json
+++ b/packages/types/CHANGELOG.json
@@ -1,5 +1,18 @@
[
{
+ "version": "1.4.0",
+ "changes": [
+ {
+ "note": "Add `LengthMismatch` and `LengthGreaterThan3Required` revert reasons",
+ "pr": 1224
+ },
+ {
+ "note": "Add RevertReasons for DutchAuction contract",
+ "pr": 1225
+ }
+ ]
+ },
+ {
"version": "1.3.0",
"changes": [
{
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index 1a86f45e6..6b728af71 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',
@@ -235,6 +237,12 @@ export enum RevertReason {
TxFullyConfirmed = 'TX_FULLY_CONFIRMED',
TxNotFullyConfirmed = 'TX_NOT_FULLY_CONFIRMED',
TimeLockIncomplete = 'TIME_LOCK_INCOMPLETE',
+ // DutchAuction
+ AuctionInvalidAmount = 'INVALID_AMOUNT',
+ AuctionExpired = 'AUCTION_EXPIRED',
+ AuctionNotStarted = 'AUCTION_NOT_STARTED',
+ AuctionInvalidBeginTime = 'INVALID_BEGIN_TIME',
+ InvalidAssetData = 'INVALID_ASSET_DATA',
}
export enum StatusCodes {
diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index 8c6fb124f..08801a891 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -1,5 +1,15 @@
[
{
+ "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",
"changes": [
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
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..13cc87e2a
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts
@@ -0,0 +1,58 @@
+import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
+
+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';
+
+import { DataTypeFactory } from './interfaces';
+
+export abstract class DataType {
+ 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_ = _.isUndefined(rules) ? constants.DEFAULT_ENCODING_RULES : rules;
+ const calldata = new Calldata(rules_);
+ if (!_.isUndefined(selector)) {
+ calldata.setSelector(selector);
+ }
+ const block = this.generateCalldataBlock(value);
+ calldata.setRoot(block);
+ const encodedCalldata = calldata.toString();
+ return encodedCalldata;
+ }
+
+ public decode(calldata: string, rules?: DecodingRules, selector?: string): any {
+ 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}'.`,
+ );
+ }
+ const hasSelector = !_.isUndefined(selector);
+ const rawCalldata = new RawCalldata(calldata, hasSelector);
+ const rules_ = _.isUndefined(rules) ? constants.DEFAULT_DECODING_RULES : 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/interfaces.ts b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
new file mode 100644
index 000000000..2f2f60871
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/interfaces.ts
@@ -0,0 +1,19 @@
+import { DataItem } from 'ethereum-types';
+
+import { RawCalldata } from '../calldata/raw_calldata';
+
+import { DataType } from './data_type';
+
+export interface DataTypeFactory {
+ create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
+}
+
+export interface DataTypeStaticInterface {
+ matchType: (type: string) => boolean;
+ 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/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
new file mode 100644
index 000000000..a091e55b9
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -0,0 +1,40 @@
+import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
+
+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';
+import { DataTypeFactory } from '../interfaces';
+
+export abstract class AbstractBlobDataType extends DataType {
+ protected _sizeKnownAtCompileTime: boolean;
+
+ public constructor(dataItem: DataItem, factory: DataTypeFactory, sizeKnownAtCompileTime: boolean) {
+ super(dataItem, factory);
+ this._sizeKnownAtCompileTime = sizeKnownAtCompileTime;
+ }
+
+ 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 BlobCalldataBlock(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._sizeKnownAtCompileTime;
+ }
+
+ public abstract encodeValue(value: any): Buffer;
+ public abstract decodeValue(calldata: RawCalldata): any;
+}
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..0f3c55280
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -0,0 +1,54 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+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';
+
+import { DataType } from '../data_type';
+import { DataTypeFactory } from '../interfaces';
+
+export abstract class AbstractPointerDataType extends DataType {
+ protected _destination: DataType;
+ protected _parent: DataType;
+
+ public constructor(dataItem: DataItem, factory: DataTypeFactory, destination: DataType, parent: DataType) {
+ super(dataItem, factory);
+ this._destination = destination;
+ this._parent = parent;
+ }
+
+ public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PointerCalldataBlock {
+ if (_.isUndefined(parentBlock)) {
+ throw new Error(`DependentDataType requires a parent block to generate its block`);
+ }
+ const destinationBlock = this._destination.generateCalldataBlock(value, parentBlock);
+ const name = this.getDataItem().name;
+ const signature = this.getSignature();
+ const parentName = parentBlock.getName();
+ const block = new PointerCalldataBlock(name, signature, parentName, destinationBlock, 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._destination.generateValue(calldata, rules);
+ calldata.setOffset(currentOffset);
+ 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
new file mode 100644
index 000000000..089d04659
--- /dev/null
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -0,0 +1,218 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../../../configured_bignumber';
+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';
+
+import { DataType } from '../data_type';
+import { DataTypeFactory, MemberIndexByName } from '../interfaces';
+
+import { AbstractPointerDataType } from './pointer';
+
+export abstract class AbstractSetDataType 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 && !_.isUndefined(arrayLength)) {
+ [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): SetCalldataBlock {
+ 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;
+ // Case 1: This is an array of undefined length, which means that `this._members` was not
+ // 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);
+ 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];
+ const memberValue = member.generateValue(calldata, rules);
+ (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 {
+ // An array with an undefined length is never static.
+ 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 AbstractPointerDataType;
+ });
+ const isStatic = _.isUndefined(dependentMember);
+ return isStatic;
+ }
+
+ 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(
+ `Expected array of ${JSON.stringify(
+ this._arrayLength,
+ )} elements, but got array of length ${JSON.stringify(value.length)}`,
+ );
+ }
+ // Create a new calldata block for this set.
+ const parentName = _.isUndefined(parentBlock) ? '' : parentBlock.getName();
+ 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)) {
+ [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,
+ );
+ block.setHeader(lenBuf);
+ }
+ // Create blocks for members of set.
+ const memberCalldataBlocks: CalldataBlock[] = [];
+ _.each(members, (member: DataType, idx: number) => {
+ const memberBlock = member.generateCalldataBlock(value[idx], block);
+ memberCalldataBlocks.push(memberBlock);
+ });
+ block.setMembers(memberCalldataBlocks);
+ return block;
+ }
+
+ 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);
+ // Create blocks for members of set.
+ 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 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)}`);
+ }
+ // Associate member blocks with Set block.
+ block.setMembers(memberCalldataBlocks);
+ return 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;
+ }
+
+ 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
+ }'.`,
+ );
+ }
+ // Create one member for each component of `dataItem`
+ 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 (!_.isUndefined(components)) {
+ 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] {
+ // Create `length` members, deriving the type from `dataItem`
+ const members: DataType[] = [];
+ const memberIndexByName: MemberIndexByName = {};
+ const range = _.range(length);
+ _.each(range, (idx: number) => {
+ const memberDataItem: DataItem = {
+ type: _.isUndefined(this._arrayElementType) ? '' : this._arrayElementType,
+ 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;
+ members.push(memberType);
+ });
+ 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..219ea6c61
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts
@@ -0,0 +1,20 @@
+import { CalldataBlock } from '../calldata_block';
+
+export class BlobCalldataBlock 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/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
new file mode 100644
index 000000000..72d6a3173
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts
@@ -0,0 +1,61 @@
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { constants } from '../../utils/constants';
+
+import { CalldataBlock } from '../calldata_block';
+
+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;
+ 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 = PointerCalldataBlock._EMPTY_HEADER_SIZE;
+ const bodySizeInBytes = PointerCalldataBlock._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 = !_.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);
+ 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(PointerCalldataBlock.RAW_DATA_START);
+ rawDataComponents.push(dependencyRawData);
+ 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
new file mode 100644
index 000000000..d1abc4986
--- /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 SetCalldataBlock 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 (!_.isUndefined(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 (!_.isUndefined(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
new file mode 100644
index 000000000..5f3eee94a
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/calldata.ts
@@ -0,0 +1,243 @@
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { constants } from '../utils/constants';
+import { EncodingRules } from '../utils/rules';
+
+import { PointerCalldataBlock } from './blocks/pointer';
+import { SetCalldataBlock } from './blocks/set';
+import { CalldataBlock } from './calldata_block';
+import { CalldataIterator, ReverseCalldataIterator } from './iterator';
+
+export class Calldata {
+ private readonly _rules: EncodingRules;
+ private _selector: string;
+ private _root: CalldataBlock | undefined;
+
+ public constructor(rules: EncodingRules) {
+ this._rules = rules;
+ this._selector = '';
+ this._root = undefined;
+ }
+ /**
+ * 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 (!_.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}'`);
+ }
+ 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 (_.isUndefined(this._root)) {
+ 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._toHumanReadableCallData() : this._toEvmCompatibeCallDataHex();
+ 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 (_.isUndefined(this._root)) {
+ throw new Error('expected root');
+ }
+ 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 PointerCalldataBlock) {
+ 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;
+ }
+ // This block has not been seen. Record its hash.
+ const blockHashBuf = block.computeHash();
+ const blockHash = ethUtil.bufferToHex(blockHashBuf);
+ if (!(blockHash in blocksByHash)) {
+ blocksByHash[blockHash] = block;
+ }
+ }
+ }
+ private _toEvmCompatibeCallDataHex(): string {
+ // Sanity check: must have a root block.
+ if (_.isUndefined(this._root)) {
+ throw new Error('expected root');
+ }
+ // 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);
+ for (const block of iterator) {
+ valueBufs.push(block.toBuffer());
+ }
+ // Create hex from buffer array.
+ const combinedBuffers = Buffer.concat(valueBufs);
+ const hexValue = ethUtil.bufferToHex(combinedBuffers);
+ return hexValue;
+ }
+ /**
+ * Returns human-readable 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 _toHumanReadableCallData(): string {
+ // Sanity check: must have a root block.
+ if (_.isUndefined(this._root)) {
+ 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;
+ 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}.`, '');
+ // Resulting line will be <offsetStr><valueStr><nameStr>
+ let offsetStr = '';
+ let valueStr = '';
+ let nameStr = '';
+ 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);
+ valueStr = ' '.repeat(valuePadding);
+ nameStr = `### ${prettyName.padEnd(namePadding)}`;
+ lineStr = `\n${offsetStr}${valueStr}${nameStr}`;
+ } else {
+ // This block has at least one word of value.
+ offsetStr = `0x${offset.toString(constants.HEX_BASE)}`.padEnd(offsetPadding);
+ valueStr = ethUtil
+ .stripHexPrefix(
+ ethUtil.bufferToHex(
+ block.toBuffer().slice(evmWordStartIndex, constants.EVM_WORD_WIDTH_IN_BYTES),
+ ),
+ )
+ .padEnd(valuePadding);
+ if (block instanceof SetCalldataBlock) {
+ nameStr = `### ${prettyName.padEnd(namePadding)}`;
+ lineStr = `\n${offsetStr}${valueStr}${nameStr}`;
+ } else {
+ nameStr = ` ${prettyName.padEnd(namePadding)}`;
+ 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);
+ valueStr = ethUtil
+ .stripHexPrefix(
+ ethUtil.bufferToHex(block.toBuffer().slice(j, j + constants.EVM_WORD_WIDTH_IN_BYTES)),
+ )
+ .padEnd(valuePadding);
+ nameStr = ' '.repeat(namePadding);
+ lineStr = `${lineStr}\n${offsetStr}${valueStr}${nameStr}`;
+ }
+ // Append to hex value
+ hexValue = `${hexValue}\n${lineStr}`;
+ offset += size;
+ }
+ 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/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts
new file mode 100644
index 000000000..333b32b4f
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/iterator.ts
@@ -0,0 +1,114 @@
+/* tslint:disable max-classes-per-file */
+import * as _ from 'lodash';
+
+import { Queue } from '../utils/queue';
+
+import { BlobCalldataBlock } from './blocks/blob';
+import { PointerCalldataBlock } from './blocks/pointer';
+import { SetCalldataBlock } from './blocks/set';
+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 implements Iterable<CalldataBlock> {
+ 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 SetCalldataBlock)) {
+ 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 PointerCalldataBlock && _.isUndefined(member.getAlias())) {
+ 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 [Symbol.iterator](): { next: () => IteratorResult<CalldataBlock> } {
+ return {
+ next: () => {
+ const nextBlock = this.nextBlock();
+ if (!_.isUndefined(nextBlock)) {
+ return {
+ value: nextBlock,
+ done: false,
+ };
+ }
+ return {
+ done: true,
+ value: new BlobCalldataBlock('', '', '', new Buffer('')),
+ };
+ },
+ };
+ }
+
+ public abstract nextBlock(): CalldataBlock | undefined;
+}
+
+export class CalldataIterator extends BaseIterator {
+ public constructor(root: CalldataBlock) {
+ super(root);
+ }
+
+ public nextBlock(): CalldataBlock | undefined {
+ return this._queue.popFront();
+ }
+}
+
+export class ReverseCalldataIterator extends BaseIterator {
+ public constructor(root: CalldataBlock) {
+ super(root);
+ }
+
+ public nextBlock(): CalldataBlock | undefined {
+ return this._queue.popBack();
+ }
+}
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..189841989
--- /dev/null
+++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts
@@ -0,0 +1,82 @@
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { constants } from '../utils/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;
+
+ public constructor(value: string | Buffer, hasSelector: boolean = true) {
+ // Sanity check
+ if (typeof value === 'string' && !_.startsWith(value, '0x')) {
+ throw new Error(`Expected raw calldata to start with '0x'`);
+ }
+ // 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 {
+ 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.popFront();
+ }
+
+ public getOffset(): number {
+ return this._offset;
+ }
+
+ public toAbsoluteOffset(relativeOffset: number): number {
+ const scopeOffset = this._scopes.peekFront();
+ if (_.isUndefined(scopeOffset)) {
+ 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/evm_data_type_factory.ts b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
new file mode 100644
index 000000000..4cc124e0a
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_type_factory.ts
@@ -0,0 +1,132 @@
+/* tslint:disable max-classes-per-file */
+import { DataItem, MethodAbi } from 'ethereum-types';
+import * as _ from 'lodash';
+
+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';
+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 BoolDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class Int extends IntDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class UInt extends UIntDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class StaticBytes extends StaticBytesDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class DynamicBytes extends DynamicBytesDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class String extends StringDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class Pointer extends PointerDataType {
+ public constructor(destDataType: DataType, parentDataType: DataType) {
+ super(destDataType, parentDataType, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class Tuple extends TupleDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class Array extends ArrayDataType {
+ public constructor(dataItem: DataItem) {
+ super(dataItem, EvmDataTypeFactory.getInstance());
+ }
+}
+
+export class Method extends MethodDataType {
+ public constructor(abi: MethodAbi) {
+ super(abi, EvmDataTypeFactory.getInstance());
+ }
+}
+
+/* tslint:disable no-construct */
+export class EvmDataTypeFactory implements DataTypeFactory {
+ private static _instance: DataTypeFactory;
+
+ public static getInstance(): DataTypeFactory {
+ if (!EvmDataTypeFactory._instance) {
+ EvmDataTypeFactory._instance = new EvmDataTypeFactory();
+ }
+ return EvmDataTypeFactory._instance;
+ }
+
+ /* tslint:disable prefer-function-over-method */
+ public create(dataItem: DataItem, parentDataType?: DataType): DataType {
+ // Create data type
+ let dataType: undefined | DataType;
+ if (Array.matchType(dataItem.type)) {
+ dataType = new Array(dataItem);
+ } else if (Address.matchType(dataItem.type)) {
+ dataType = new Address(dataItem);
+ } else if (Bool.matchType(dataItem.type)) {
+ dataType = new Bool(dataItem);
+ } else if (Int.matchType(dataItem.type)) {
+ dataType = new Int(dataItem);
+ } else if (UInt.matchType(dataItem.type)) {
+ dataType = new UInt(dataItem);
+ } else if (StaticBytes.matchType(dataItem.type)) {
+ dataType = new StaticBytes(dataItem);
+ } else if (Tuple.matchType(dataItem.type)) {
+ dataType = new Tuple(dataItem);
+ } else if (DynamicBytes.matchType(dataItem.type)) {
+ dataType = new DynamicBytes(dataItem);
+ } else if (String.matchType(dataItem.type)) {
+ dataType = new String(dataItem);
+ }
+ // @TODO: DataTypeement Fixed/UFixed types
+ if (_.isUndefined(dataType)) {
+ throw new Error(`Unrecognized data type: '${dataItem.type}'`);
+ } else if (!_.isUndefined(parentDataType) && !dataType.isStatic()) {
+ const pointerToDataType = new Pointer(dataType, parentDataType);
+ return pointerToDataType;
+ }
+ 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
new file mode 100644
index 000000000..88846b1fa
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts
@@ -0,0 +1,49 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
+import { RawCalldata } from '../calldata/raw_calldata';
+import { constants } from '../utils/constants';
+
+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 -
+ AddressDataType._ADDRESS_SIZE_IN_BYTES;
+
+ public static matchType(type: string): boolean {
+ return type === SolidityTypes.Address;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ 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}`);
+ }
+ }
+
+ // Disable prefer-function-over-method for inherited abstract methods.
+ /* tslint:disable prefer-function-over-method */
+ public encodeValue(value: string): Buffer {
+ if (!ethUtil.isValidAddress(value)) {
+ throw new Error(`Invalid address: '${value}'`);
+ }
+ const valueBuf = ethUtil.toBuffer(value);
+ const encodedValueBuf = ethUtil.setLengthLeft(valueBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
+ return encodedValueBuf;
+ }
+
+ public decodeValue(calldata: RawCalldata): string {
+ const valueBufPadded = calldata.popWord();
+ const valueBuf = valueBufPadded.slice(AddressDataType._DECODED_ADDRESS_OFFSET_IN_BYTES);
+ const value = ethUtil.bufferToHex(valueBuf);
+ return value;
+ }
+
+ public getSignature(): string {
+ return SolidityTypes.Address;
+ }
+ /* tslint:enable prefer-function-over-method */
+}
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..7595cb667
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts
@@ -0,0 +1,64 @@
+import { DataItem } from 'ethereum-types';
+import * as _ from 'lodash';
+
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractSetDataType } from '../abstract_data_types/types/set';
+import { constants } from '../utils/constants';
+
+export class ArrayDataType extends AbstractSetDataType {
+ private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$');
+ private readonly _arraySignature: string;
+ private readonly _elementType: string;
+
+ public static matchType(type: string): boolean {
+ return ArrayDataType._MATCHER.test(type);
+ }
+
+ private static _decodeElementTypeAndLengthFromType(type: string): [string, undefined | number] {
+ 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])) {
+ throw new Error(`Could not parse array type: ${type}`);
+ } else if (_.isUndefined(matches[2])) {
+ 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);
+ return [arrayElementType, arrayLength];
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ // Construct parent
+ const isArray = true;
+ const [arrayElementType, arrayLength] = ArrayDataType._decodeElementTypeAndLengthFromType(dataItem.type);
+ super(dataItem, dataTypeFactory, isArray, arrayLength, arrayElementType);
+ // Set array properties
+ this._elementType = arrayElementType;
+ this._arraySignature = this._computeSignature();
+ }
+
+ public getSignature(): string {
+ return this._arraySignature;
+ }
+
+ private _computeSignature(): string {
+ // Compute signature for a single array element
+ const elementDataItem: DataItem = {
+ type: this._elementType,
+ name: 'N/A',
+ };
+ const elementComponents = this.getDataItem().components;
+ if (!_.isUndefined(elementComponents)) {
+ elementDataItem.components = elementComponents;
+ }
+ const elementDataType = this.getFactory().create(elementDataItem);
+ const elementSignature = elementDataType.getSignature();
+ // Construct signature for array of type `element`
+ if (_.isUndefined(this._arrayLength)) {
+ return `${elementSignature}[]`;
+ } else {
+ return `${elementSignature}[${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..d713d5a94
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts
@@ -0,0 +1,53 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+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/raw_calldata';
+import { constants } from '../utils/constants';
+
+export class BoolDataType extends AbstractBlobDataType {
+ private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+
+ public static matchType(type: string): boolean {
+ return type === SolidityTypes.Bool;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ 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}`);
+ }
+ }
+
+ // 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(
+ 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);
+ /* tslint:enable boolean-naming */
+ return value;
+ }
+
+ public getSignature(): string {
+ 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
new file mode 100644
index 000000000..5277efd6c
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts
@@ -0,0 +1,72 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
+import { RawCalldata } from '../calldata/raw_calldata';
+import { constants } from '../utils/constants';
+
+export class DynamicBytesDataType extends AbstractBlobDataType {
+ private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+
+ public static matchType(type: string): boolean {
+ return type === SolidityTypes.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, DynamicBytesDataType._SIZE_KNOWN_AT_COMPILE_TIME);
+ if (!DynamicBytesDataType.matchType(dataItem.type)) {
+ throw new Error(`Tried to instantiate Dynamic Bytes with bad input: ${dataItem}`);
+ }
+ }
+
+ // 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
+ 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 lengthBuf = ethUtil.toBuffer(valueBuf.byteLength);
+ const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, constants.EVM_WORD_WIDTH_IN_BYTES);
+ // 2/3 Construct the value
+ DynamicBytesDataType._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);
+ // 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);
+ DynamicBytesDataType._sanityCheckValue(value);
+ return value;
+ }
+
+ public getSignature(): string {
+ 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
new file mode 100644
index 000000000..f1dcf5ea1
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts
@@ -0,0 +1,59 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+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/raw_calldata';
+import { constants } from '../utils/constants';
+import * as EncoderMath from '../utils/math';
+
+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}$',
+ );
+ private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+ private static readonly _MAX_WIDTH: number = 256;
+ 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 IntDataType._MATCHER.test(type);
+ }
+
+ private static _decodeWidthFromType(type: string): number {
+ const matches = IntDataType._MATCHER.exec(type);
+ const width =
+ !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
+ ? parseInt(matches[1], constants.DEC_BASE)
+ : IntDataType._DEFAULT_WIDTH;
+ return width;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ 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 = 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);
+ }
+
+ public encodeValue(value: BigNumber | string | number): Buffer {
+ const encodedValue = EncoderMath.safeEncodeNumericValue(value, this._minValue, this._maxValue);
+ return encodedValue;
+ }
+
+ public decodeValue(calldata: RawCalldata): BigNumber {
+ const valueBuf = calldata.popWord();
+ const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue);
+ return value;
+ }
+
+ public getSignature(): string {
+ return `${SolidityTypes.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..b1cd1377f
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts
@@ -0,0 +1,72 @@
+import { DataItem, MethodAbi } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+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 AbstractSetDataType {
+ private readonly _methodSignature: string;
+ private readonly _methodSelector: string;
+ private readonly _returnDataType: DataType;
+
+ public constructor(abi: MethodAbi, dataTypeFactory: DataTypeFactory) {
+ const methodDataItem = { type: 'method', name: abi.name, components: abi.inputs };
+ super(methodDataItem, dataTypeFactory);
+ this._methodSignature = this._computeSignature();
+ this._methodSelector = this._computeSelector();
+ const returnDataItem: DataItem = { type: 'tuple', name: abi.name, components: abi.outputs };
+ this._returnDataType = new TupleDataType(returnDataItem, this.getFactory());
+ }
+
+ public encode(value: any, rules?: EncodingRules): string {
+ const calldata = super.encode(value, rules, this._methodSelector);
+ return calldata;
+ }
+
+ public decode(calldata: string, rules?: DecodingRules): any[] | object {
+ const value = super.decode(calldata, rules, this._methodSelector);
+ return value;
+ }
+
+ public encodeReturnValues(value: any, rules?: EncodingRules): string {
+ const returnData = this._returnDataType.encode(value, rules);
+ return returnData;
+ }
+
+ public decodeReturnValues(returndata: string, rules?: DecodingRules): any {
+ const returnValues = this._returnDataType.decode(returndata, 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/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
new file mode 100644
index 000000000..389e75927
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -0,0 +1,17 @@
+import { DataItem } from 'ethereum-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 AbstractPointerDataType {
+ 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._destination.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..2e371c505
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts
@@ -0,0 +1,78 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
+import { RawCalldata } from '../calldata/raw_calldata';
+import { constants } from '../utils/constants';
+
+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))$',
+ );
+ private static readonly _DEFAULT_WIDTH = 1;
+ private readonly _width: number;
+
+ public static matchType(type: string): boolean {
+ return StaticBytesDataType._MATCHER.test(type);
+ }
+
+ private static _decodeWidthFromType(type: string): number {
+ const matches = StaticBytesDataType._MATCHER.exec(type);
+ const width =
+ !_.isNull(matches) && matches.length === 3 && !_.isUndefined(matches[2])
+ ? parseInt(matches[2], constants.DEC_BASE)
+ : StaticBytesDataType._DEFAULT_WIDTH;
+ return width;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ 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 = StaticBytesDataType._decodeWidthFromType(dataItem.type);
+ }
+
+ public getSignature(): string {
+ // Note that `byte` reduces to `bytes1`
+ return `${SolidityTypes.Bytes}${this._width}`;
+ }
+
+ public encodeValue(value: string | Buffer): Buffer {
+ // 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 (!_.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.`);
+ }
+ }
+ 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()}`,
+ );
+ }
+ }
+}
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..91a72ad3f
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts
@@ -0,0 +1,59 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractBlobDataType } from '../abstract_data_types/types/blob';
+import { RawCalldata } from '../calldata/raw_calldata';
+import { constants } from '../utils/constants';
+
+export class StringDataType extends AbstractBlobDataType {
+ private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false;
+
+ public static matchType(type: string): boolean {
+ return type === SolidityTypes.String;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ 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}`);
+ }
+ }
+
+ // 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
+ 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 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 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;
+ }
+
+ public getSignature(): 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
new file mode 100644
index 000000000..31593c882
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts
@@ -0,0 +1,24 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+
+import { DataTypeFactory } from '../abstract_data_types/interfaces';
+import { AbstractSetDataType } from '../abstract_data_types/types/set';
+
+export class TupleDataType extends AbstractSetDataType {
+ private readonly _signature: string;
+
+ public static matchType(type: string): boolean {
+ return type === SolidityTypes.Tuple;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ super(dataItem, dataTypeFactory);
+ if (!TupleDataType.matchType(dataItem.type)) {
+ throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
+ }
+ this._signature = this._computeSignatureOfMembers();
+ }
+
+ public getSignature(): string {
+ return this._signature;
+ }
+}
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..5180f0cf3
--- /dev/null
+++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts
@@ -0,0 +1,58 @@
+import { DataItem, SolidityTypes } from 'ethereum-types';
+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/raw_calldata';
+import { constants } from '../utils/constants';
+import * as EncoderMath from '../utils/math';
+
+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}$',
+ );
+ private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true;
+ private static readonly _MAX_WIDTH: number = 256;
+ 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 UIntDataType._MATCHER.test(type);
+ }
+
+ private static _decodeWidthFromType(type: string): number {
+ const matches = UIntDataType._MATCHER.exec(type);
+ const width =
+ !_.isNull(matches) && matches.length === 2 && !_.isUndefined(matches[1])
+ ? parseInt(matches[1], constants.DEC_BASE)
+ : UIntDataType._DEFAULT_WIDTH;
+ return width;
+ }
+
+ public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
+ 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 = 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, UIntDataType._MIN_VALUE, this._maxValue);
+ return encodedValue;
+ }
+
+ public decodeValue(calldata: RawCalldata): BigNumber {
+ const valueBuf = calldata.popWord();
+ const value = EncoderMath.safeDecodeNumericValue(valueBuf, UIntDataType._MIN_VALUE, this._maxValue);
+ return value;
+ }
+
+ public getSignature(): string {
+ return `${SolidityTypes.Uint}${this._width}`;
+ }
+}
diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts
new file mode 100644
index 000000000..baf844ac6
--- /dev/null
+++ b/packages/utils/src/abi_encoder/index.ts
@@ -0,0 +1,14 @@
+export { EncodingRules, DecodingRules } from './utils/rules';
+export {
+ Address,
+ Array,
+ Bool,
+ DynamicBytes,
+ Int,
+ Method,
+ Pointer,
+ StaticBytes,
+ String,
+ Tuple,
+ UInt,
+} from './evm_data_type_factory';
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..2f43ba04d
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/constants.ts
@@ -0,0 +1,17 @@
+import { DecodingRules, EncodingRules } from './rules';
+
+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,
+ // 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 */
+};
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..d84983c5b
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/math.ts
@@ -0,0 +1,111 @@
+import BigNumber from 'bignumber.js';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { 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 isValueNegative = valueBin.length === constants.EVM_WORD_WIDTH_IN_BITS && _.startsWith(valueBin[0], '1');
+ if (!isValueNegative) {
+ 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
new file mode 100644
index 000000000..53afb7e11
--- /dev/null
+++ b/packages/utils/src/abi_encoder/utils/queue.ts
@@ -0,0 +1,39 @@
+export class Queue<T> {
+ private _store: T[] = [];
+
+ public pushBack(val: T): void {
+ this._store.push(val);
+ }
+
+ public pushFront(val: T): void {
+ this._store.unshift(val);
+ }
+
+ public popFront(): 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 mergeBack(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 peekFront(): T | undefined {
+ return this._store.length >= 0 ? this._store[0] : undefined;
+ }
+}
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..31471e97a
--- /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;
+}
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index 0723e5788..082aff6bb 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 import AbiEncoder = require('./abi_encoder');
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..9ef80a560
--- /dev/null
+++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts
@@ -0,0 +1,1007 @@
+/* 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', () => {
+ const encodingRules: AbiEncoder.EncodingRules = { optimize: false }; // optimizer is tested separately.
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000041011121300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000414151617000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000301020304000000000000000000000000000000000000000000000000000000000506070800000000000000000000000000000000000000000000000000000000091011120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021011121300000000000000000000000000000000000000000000000000000000141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011819202100000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x010203040000000000000000000000000000000000000000000000000000000005060708000000000000000000000000000000000000000000000000000000000910111200000000000000000000000000000000000000000000000000000000101112130000000000000000000000000000000000000000000000000000000014151617000000000000000000000000000000000000000000000000000000001819202100000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000401020304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040910111200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000410111213000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004141516170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041819202100000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).to.throw(`Invalid address: '${args}'`);
+ });
+ 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, encodingRules);
+ }).to.throw(`Invalid address: '${args}'`);
+ });
+ });
+
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ });
+
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = `0x8000000000000000000000000000000000000000000000000000000000000000`;
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x000000000000000000000000000000000000000000000000000000007fffffff';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000`;
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs = '0x0000000000000000000000000000000000000000000000000000000000000001';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x00000000000000000000000000000000000000000000000000000000ffffffff';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = `0x0000000000000000000000000000000000000000000000000000000000000000`;
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x0500000000000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x0001020300000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x1a18000000000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ const paddedArgs = '0x1a180000';
+ expect(decodedArgs).to.be.deep.equal(paddedArgs);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x0001020304050607080911121314151617181920212223242526272829303132';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ const paddedArgs = '0x1a18bf6100000000000000000000000000000000000000000000000000000000';
+ expect(decodedArgs).to.be.deep.equal(paddedArgs);
+ });
+ 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, encodingRules);
+ }).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, encodingRules);
+ }).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, 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 () => {
+ // 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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs =
+ '0x00000000000000000000000000000000000000000000000000000000000000041a18bf6100000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, 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 () => {
+ // 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, encodingRules);
+ }).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, encodingRules);
+ const expectedEncodedArgs =
+ '0x00000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x000000000000000000000000000000000000000000000000000000000000002861616161616161616161616161616161616161616161616161616161616161616161616161616161000000000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedEncodedArgs =
+ '0x000000000000000000000000000000000000000000000000000000000000002a30786161616161616161616161616161616161616161616161616161616161616161616161616161616100000000000000000000000000000000000000000000';
+ expect(encodedArgs).to.be.equal(expectedEncodedArgs);
+ // Decode Encoded Args and validate result
+ const decodedArgs = dataType.decode(encodedArgs);
+ 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
new file mode 100644
index 000000000..837020883
--- /dev/null
+++ b/packages/utils/test/abi_encoder/methods_test.ts
@@ -0,0 +1,366 @@
+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', () => {
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038';
+ expect(calldata).to.be.equal(expectedCalldata);
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ it('Array ABI', async () => {
+ // Generate calldata
+ const method = new AbiEncoder.Method(AbiSamples.stringAbi);
+ const args = [['five', 'six', 'seven']];
+ const calldata = method.encode(args, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedCalldata =
+ '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata);
+ expect(decodedValue).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ // Validate calldata
+ const expectedCalldata =
+ '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000';
+ expect(calldata).to.be.equal(expectedCalldata);
+ // Validate decoding
+ const decodedValue = method.decode(calldata, { structsAsObjects: true });
+ 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
new file mode 100644
index 000000000..18aa6549a
--- /dev/null
+++ b/packages/utils/test/abi_encoder/optimizer_test.ts
@@ -0,0 +1,262 @@
+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', () => {
+ const encodingRules: AbiEncoder.EncodingRules = { optimize: true };
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ expect(decodedArgs).to.be.deep.equal(args);
+ });
+ 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, encodingRules);
+ const expectedOptimizedCalldata =
+ '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000';
+ expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata);
+ // Validate decoding
+ const decodedArgs = method.decode(optimizedCalldata);
+ 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
new file mode 100644
index 000000000..a8cdd6ca3
--- /dev/null
+++ b/packages/utils/test/abi_encoder/return_values_test.ts
@@ -0,0 +1,67 @@
+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', () => {
+ 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);
+ const returnValue = '0x';
+ const decodedReturnValue = method.decodeReturnValues(returnValue);
+ const expectedDecodedReturnValue: any[] = [];
+ expect(decodedReturnValue).to.be.deep.equal(expectedDecodedReturnValue);
+ });
+ it('Single static return value', async () => {
+ // Generate Return Value
+ const method = new AbiEncoder.Method(ReturnValueAbis.singleStaticReturnValue);
+ const returnValue = ['0x01020304'];
+ const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
+ const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+ // Validate decoded return value
+ expect(decodedReturnValue).to.be.deep.equal(returnValue);
+ });
+ 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, encodingRules);
+ const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+ // Validate decoded return value
+ expect(decodedReturnValue).to.be.deep.equal(returnValue);
+ });
+ it('Single dynamic return value', async () => {
+ // Generate Return Value
+ const method = new AbiEncoder.Method(ReturnValueAbis.singleDynamicReturnValue);
+ const returnValue = ['0x01020304'];
+ const encodedReturnValue = method.encodeReturnValues(returnValue, encodingRules);
+ const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+ // Validate decoded return value
+ expect(decodedReturnValue).to.be.deep.equal(returnValue);
+ });
+ 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, encodingRules);
+ const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+ // Validate decoded return value
+ expect(decodedReturnValue).to.be.deep.equal(returnValue);
+ });
+ 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, encodingRules);
+ const decodedReturnValue = method.decodeReturnValues(encodedReturnValue);
+ // Validate decoded return value
+ expect(decodedReturnValue).to.be.deep.equal(returnValue);
+ });
+});
diff --git a/packages/contracts/test/utils/chai_setup.ts b/packages/utils/test/utils/chai_setup.ts
index 1a8733093..1a8733093 100644
--- a/packages/contracts/test/utils/chai_setup.ts
+++ b/packages/utils/test/utils/chai_setup.ts
diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json
index ad6902e33..9f5194e0d 100644
--- a/packages/web3-wrapper/CHANGELOG.json
+++ b/packages/web3-wrapper/CHANGELOG.json
@@ -6,7 +6,8 @@
"note": "Unmarshall mined transaction receipts",
"pr": 1308
}
- ]
+ ],
+ "timestamp": 1543401373
},
{
"version": "3.1.5",
diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md
index fa88eee2c..fffaf1d0a 100644
--- a/packages/web3-wrapper/CHANGELOG.md
+++ b/packages/web3-wrapper/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v3.1.6 - _November 28, 2018_
+
+ * Unmarshall mined transaction receipts (#1308)
+
## v3.1.5 - _November 21, 2018_
* Add unmarshalling of transaction receipts (#1291)
diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json
index 2eba35da7..218d85bfc 100644
--- a/packages/web3-wrapper/package.json
+++ b/packages/web3-wrapper/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/web3-wrapper",
- "version": "3.1.5",
+ "version": "3.1.6",
"engines": {
"node": ">=6.12"
},
diff --git a/packages/website/md/docs/smart_contracts/1/introduction.md b/packages/website/md/docs/smart_contracts/1/introduction.md
index 79a8f00fd..81715a3d1 100644
--- a/packages/website/md/docs/smart_contracts/1/introduction.md
+++ b/packages/website/md/docs/smart_contracts/1/introduction.md
@@ -1 +1 @@
-Welcome to the [0x smart contracts](https://github.com/0xProject/0x-monorepo/tree/development/packages/contracts) documentation! This documentation is intended for dApp developers who want to integrate 0x exchange functionality directly into their own smart contracts.
+Welcome to the [0x smart contracts](https://github.com/0xProject/0x-monorepo/tree/development/contracts/core) documentation! This documentation is intended for dApp developers who want to integrate 0x exchange functionality directly into their own smart contracts.
diff --git a/packages/website/md/docs/smart_contracts/2/introduction.md b/packages/website/md/docs/smart_contracts/2/introduction.md
index 4aa31db3d..0b4e2aac6 100644
--- a/packages/website/md/docs/smart_contracts/2/introduction.md
+++ b/packages/website/md/docs/smart_contracts/2/introduction.md
@@ -1,4 +1,4 @@
-Welcome to the [0x smart contracts](https://github.com/0xProject/0x-monorepo/tree/development/packages/contracts) documentation! This documentation is intended for dApp developers who want to integrate 0x exchange functionality directly into their own smart contracts.
+Welcome to the [0x smart contracts](https://github.com/0xProject/0x-monorepo/tree/development/contracts/core) documentation! This documentation is intended for dApp developers who want to integrate 0x exchange functionality directly into their own smart contracts.
### Helpful wiki articles:
diff --git a/packages/website/package.json b/packages/website/package.json
index 75e147168..52d5c8f96 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/website",
- "version": "0.0.60",
+ "version": "0.0.61",
"engines": {
"node": ">=6.12"
},
@@ -20,17 +20,17 @@
"author": "Fabio Berger",
"license": "Apache-2.0",
"dependencies": {
- "@0x/contract-wrappers": "^4.1.0",
+ "@0x/contract-wrappers": "^4.1.1",
"@0x/json-schemas": "^2.1.2",
- "@0x/order-utils": "^3.0.3",
- "@0x/react-docs": "^1.0.19",
- "@0x/react-shared": "^1.0.22",
- "@0x/subproviders": "^2.1.5",
+ "@0x/order-utils": "^3.0.4",
+ "@0x/react-docs": "^1.0.20",
+ "@0x/react-shared": "^1.0.23",
+ "@0x/subproviders": "^2.1.6",
"@0x/types": "^1.3.0",
"@0x/typescript-typings": "^3.0.4",
"@0x/utils": "^2.0.6",
- "@0x/web3-wrapper": "^3.1.5",
"@types/styled-components": "^4.1.1",
+ "@0x/web3-wrapper": "^3.1.6",
"accounting": "^0.4.1",
"basscss": "^8.0.3",
"blockies": "^0.0.2",
diff --git a/packages/website/public/images/instant/dai_screenshot.png b/packages/website/public/images/instant/dai_screenshot.png
new file mode 100644
index 000000000..02aefc909
--- /dev/null
+++ b/packages/website/public/images/instant/dai_screenshot.png
Binary files differ
diff --git a/packages/website/public/images/instant/feature_1.svg b/packages/website/public/images/instant/feature_1.svg
new file mode 100644
index 000000000..cca58d9b9
--- /dev/null
+++ b/packages/website/public/images/instant/feature_1.svg
@@ -0,0 +1,33 @@
+<svg width="343" height="127" viewBox="0 0 343 127" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="22" cy="101" r="22" fill="#0057FF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9276 102.3C16.7747 102.3 17.5795 102.47 18.3419 102.81C19.0873 103.133 19.7396 103.576 20.2986 104.137C20.8577 104.698 21.2982 105.353 21.6201 106.101C21.959 106.867 22.1284 107.675 22.1284 108.525C22.1284 109.392 21.9675 110.2 21.6455 110.949C21.3067 111.697 20.8577 112.356 20.2986 112.926C19.7395 113.496 19.0873 113.942 18.3419 114.265C17.5795 114.588 16.7747 114.75 15.9276 114.75C15.0635 114.75 14.2589 114.588 13.5133 114.265C12.7679 113.942 12.1114 113.496 11.5438 112.926C10.9763 112.356 10.5315 111.697 10.2096 110.949C9.88772 110.2 9.72677 109.392 9.72677 108.525C9.72677 107.675 9.88772 106.867 10.2096 106.101C10.5315 105.353 10.9763 104.698 11.5438 104.137C12.1114 103.576 12.7679 103.125 13.5133 102.785C14.2588 102.462 15.0635 102.3 15.9276 102.3ZM15.9276 112.582C17.0289 112.582 17.9734 112.186 18.7612 111.395C19.549 110.604 19.9429 109.648 19.9429 108.525C19.9429 107.42 19.549 106.471 18.7612 105.68C17.9734 104.89 17.0288 104.494 15.9276 104.494C14.8094 104.494 13.8564 104.89 13.0686 105.68C12.2807 106.471 11.8868 107.42 11.8868 108.525C11.8868 109.648 12.2807 110.604 13.0686 111.395C13.8564 112.186 14.8093 112.582 15.9276 112.582ZM29.5492 88.625C30.4132 88.625 31.2179 88.7866 31.9634 89.1097C32.7089 89.4329 33.3654 89.8794 33.9329 90.4491C34.5005 91.0189 34.9452 91.678 35.2671 92.4263C35.5891 93.1747 35.75 93.9826 35.75 94.85C35.75 95.7004 35.5891 96.5084 35.2671 97.2737C34.9452 98.0221 34.5005 98.6769 33.9329 99.2381C33.3654 99.7994 32.7089 100.25 31.9634 100.59C31.218 100.913 30.4132 101.075 29.5492 101.075C28.7021 101.075 27.8973 100.913 27.1349 100.59C26.3894 100.25 25.7372 99.7994 25.1781 99.2381C24.6191 98.6768 24.1701 98.022 23.8312 97.2737C23.5093 96.5083 23.3484 95.7004 23.3484 94.85C23.3484 93.9826 23.5093 93.1748 23.8312 92.4263C24.1701 91.678 24.619 91.0189 25.1781 90.4491C25.7372 89.8794 26.3895 89.4329 27.1349 89.1097C27.8973 88.7866 28.7021 88.625 29.5492 88.625ZM29.5492 98.881C30.6674 98.881 31.6204 98.4856 32.4082 97.6947C33.1961 96.9038 33.59 95.9555 33.59 94.85C33.59 93.7275 33.1961 92.7707 32.4082 91.9798C31.6204 91.189 30.6675 90.7935 29.5492 90.7935C28.4479 90.7935 27.5034 91.1889 26.7156 91.9798C25.9278 92.7707 25.5339 93.7274 25.5339 94.85C25.5339 95.9556 25.9278 96.9038 26.7156 97.6947C27.5034 98.4856 28.448 98.881 29.5492 98.881ZM15.1398 88.625H22.2046V90.7936H20.629C21.0864 91.3379 21.4465 91.9502 21.7091 92.6305C21.9717 93.3108 22.103 94.0337 22.103 94.7991V94.8502C22.103 95.7176 21.9336 96.5254 21.5947 97.2738C21.2728 98.0392 20.8281 98.7068 20.2605 99.2766C19.6929 99.8464 19.0364 100.293 18.291 100.616C17.5286 100.939 16.7154 101.101 15.8513 101.101C14.9872 101.101 14.1825 100.939 13.437 100.616C12.6746 100.293 12.0139 99.8464 11.4548 99.2766C10.8957 98.7068 10.4467 98.0392 10.1079 97.2738C9.78595 96.5255 9.625 95.7176 9.625 94.8502C9.625 94.0337 9.78595 93.2684 10.1079 92.554C10.4298 91.8396 10.8491 91.2061 11.3658 90.6534C11.8826 90.1006 12.4713 89.6456 13.132 89.2885C13.7928 88.9313 14.462 88.7187 15.1397 88.6506L15.1398 88.625ZM19.9429 94.8501C19.9429 93.7276 19.549 92.7708 18.7611 91.9799C17.9733 91.189 17.0287 90.7936 15.9275 90.7936C14.8093 90.7936 13.8563 91.189 13.0685 91.9799C12.2807 92.7708 11.8868 93.7274 11.8868 94.8501C11.8868 95.9557 12.2807 96.9038 13.0685 97.6947C13.8563 98.4856 14.8092 98.8811 15.9275 98.8811C17.0288 98.8811 17.9733 98.4856 18.7611 97.6947C19.5489 96.9039 19.9429 95.9556 19.9429 94.8501Z" fill="white"/>
+<circle cx="75.5" cy="25.5" r="22.5" fill="#F08839"/>
+<path d="M56.8066 31.7309C61.6528 31.5578 71.2413 31.7309 72.9028 33.8078C74.9797 36.404 62.5182 39.5193 72.9028 40.5578C80.4452 41.312 83.4605 43.327 83.8066 44.1924" stroke="white" stroke-width="1.73077"/>
+<circle cx="75.4997" cy="25.5002" r="19.9038" stroke="white" stroke-width="1.73077"/>
+<circle cx="72.039" cy="13.3847" r="4.32692" stroke="white" stroke-width="1.73077"/>
+<path d="M56.2891 26.0186C56.6352 26.3647 57.4314 26.7455 57.8468 25.4993C58.2621 24.2532 60.0968 21.5186 60.9621 20.307H64.0775L66.1544 26.0186C67.1929 25.8455 69.3737 25.4993 69.7891 25.4993C70.3083 25.4993 71.3468 26.0186 71.866 26.0186M71.866 26.0186C72.3852 26.0186 73.9429 23.9416 74.9814 23.9416C76.0198 23.9416 79.1352 26.0186 79.1352 25.4993C79.1352 24.9801 81.7314 22.3839 82.2506 21.3455C82.666 20.5147 83.8083 19.9609 84.3275 19.7878C84.8468 19.9609 85.8852 20.2032 85.8852 19.7878C85.8852 19.2686 86.4044 18.7493 87.4429 20.307C88.4814 21.8647 90.0391 23.9416 90.5583 23.9416C91.0775 23.9416 91.5968 23.9416 92.116 24.4609C92.5314 24.8762 94.0198 26.3647 94.7121 27.057L95.5 28M71.866 26.0186L70.3083 29.1339" stroke="white" stroke-width="1.73077"/>
+<path d="M85.885 33.9376C85.885 35.2995 84.9901 35.7159 83.7215 35.8374C83.3207 35.8758 82.8825 35.8847 82.4235 35.8847C81.9644 35.8847 81.5262 35.8758 81.1254 35.8374C79.8568 35.7159 78.9619 35.2995 78.9619 33.9376C78.9619 32.1453 80.5117 30.6924 82.4235 30.6924C84.3352 30.6924 85.885 32.1453 85.885 33.9376Z" stroke="white" stroke-width="1.73077"/>
+<path d="M91.0771 36.3173C91.0771 37.2252 90.4059 37.5028 89.4545 37.5838C89.1538 37.6094 88.8252 37.6153 88.4809 37.6153C88.1366 37.6153 87.808 37.6094 87.5074 37.5838C86.5559 37.5028 85.8848 37.2252 85.8848 36.3173C85.8848 35.1224 87.0471 34.1538 88.4809 34.1538C89.9147 34.1538 91.0771 35.1224 91.0771 36.3173Z" stroke="white" stroke-width="1.73077"/>
+<circle cx="322.5" cy="98.5" r="20.5" fill="#F2B350"/>
+<rect x="322.499" y="88.1144" width="14.6871" height="14.6871" transform="rotate(45 322.499 88.1144)" stroke="white" stroke-width="3.15385"/>
+<rect x="322.499" y="94.2949" width="5.94697" height="5.94697" transform="rotate(45 322.499 94.2949)" fill="white"/>
+<path d="M335.115 98.4998L322.499 111.115L309.884 98.4998H335.115Z" fill="white"/>
+<circle cx="274" cy="26" r="21" fill="#9E19A0"/>
+<path d="M268.973 27.3501C268.829 25.8594 270.406 23.8901 272.06 23.1905C273.715 22.4909 274.124 20.8111 274.124 20.8111L273.999 12.269" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
+<path d="M274.125 40.027V36.6055C274.125 36.6055 273.637 34.5659 275.292 33.8663C276.253 33.4599 277.23 33.8663 278.547 31.6665" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
+<path d="M262.567 32.8566L265.863 30.707C265.863 30.707 268.146 29.9997 269.476 31.197C270.368 32.0011 270.625 32.9673 272.061 33.1987" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
+<path d="M285.929 32.3543C285.929 32.3543 282.656 31.2176 281.559 30.5071C280.461 29.7966 279.769 29.6631 279.169 27.1944C278.751 25.4729 277.422 24.0452 275.938 23.9409" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M275.494 12.3748C274.88 11.2696 273.293 11.2649 272.673 12.3664L261.859 31.589C261.426 32.3596 261.692 33.3356 262.457 33.7788L273.307 40.0648C273.812 40.3574 274.436 40.3548 274.939 40.0579L285.57 33.7788C286.323 33.3338 286.585 32.3696 286.161 31.6043L275.494 12.3748Z" stroke="white" stroke-width="1.61538" stroke-miterlimit="10" stroke-linecap="round"/>
+<circle cx="119.5" cy="102.5" r="19.5" fill="#68CCBB"/>
+<path d="M131.499 109.423V96.4901C131.499 95.8739 130.797 95.5206 130.302 95.8878L122.469 101.698C122.278 101.84 122.166 102.063 122.166 102.301V110" stroke="white" stroke-width="2.25" stroke-linecap="round"/>
+<path d="M107.501 109.423V96.4901C107.501 95.8739 108.203 95.5206 108.698 95.8878L116.531 101.698C116.722 101.84 116.834 102.063 116.834 102.301V110" stroke="white" stroke-width="2.25" stroke-linecap="round"/>
+<path d="M222.5 125.557C224.047 126.45 225.953 126.45 227.5 125.557L245.883 114.943C247.43 114.05 248.383 112.4 248.383 110.613V89.3867C248.383 87.6004 247.43 85.9498 245.883 85.0566L227.5 74.4434C225.953 73.5502 224.047 73.5502 222.5 74.4434L204.117 85.0566C202.57 85.9498 201.617 87.6004 201.617 89.3867V110.613C201.617 112.4 202.57 114.05 204.117 114.943L222.5 125.557Z" fill="#FF5D3A"/>
+<path d="M213.397 96.7922L213.829 88L219.337 91.1811C223.063 89.3156 227.01 89.296 230.751 91.132L236.195 88V96.4241C236.985 97.9655 237.397 99.669 237.397 101.402C237.378 107.828 231.781 113.037 224.874 113.037C217.967 113.037 212.371 107.813 212.371 101.402C212.371 99.8064 212.719 98.2355 213.397 96.7922Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M232.003 99.3155C231.551 98.1177 229.632 98.2993 229.151 99.3155" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M221.738 99.3155C221.287 98.1177 219.367 98.2993 218.886 99.3155" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M226.951 103.307H223.942" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M225.443 103.307V104.809" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M226.734 108.471C226.327 108.746 225.34 109.203 223.941 108.52" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M174.169 1.04473C172.798 0.384526 171.202 0.384527 169.831 1.04473L153.06 9.12104C151.689 9.78124 150.693 11.0298 150.355 12.5133L146.213 30.6606C145.874 32.144 146.23 33.701 147.178 34.8906L158.784 49.4436C159.733 50.6333 161.171 51.3262 162.693 51.3262L181.307 51.3262C182.829 51.3262 184.267 50.6333 185.216 49.4436L196.822 34.8906C197.77 33.701 198.126 32.144 197.787 30.6606L193.645 12.5133C193.307 11.0298 192.311 9.78125 190.94 9.12104L174.169 1.04473Z" fill="#3AC4FF"/>
+<path d="M161 22.12V37H169.186M161 22.12H183M161 22.12L171.744 13L183 22.12M183 22.12V37H175.326M175.326 37V29.32H169.186V37M175.326 37H169.186" stroke="white" stroke-width="2"/>
+</svg>
diff --git a/packages/website/public/images/instant/feature_2.svg b/packages/website/public/images/instant/feature_2.svg
new file mode 100644
index 000000000..a313872b2
--- /dev/null
+++ b/packages/website/public/images/instant/feature_2.svg
@@ -0,0 +1,15 @@
+<svg width="209" height="112" viewBox="0 0 209 112" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="32" width="178.035" height="77.5613" rx="3.29952" fill="#8397DE" stroke="#5265AA" stroke-width="4"/>
+<path d="M121.491 69.9311C121.491 88.7841 107.718 103.915 90.9058 103.915C74.0938 103.915 60.3203 88.7841 60.3203 69.9311C60.3203 51.0782 74.0938 35.9473 90.9058 35.9473C107.718 35.9473 121.491 51.0782 121.491 69.9311Z" fill="#6E80BF" stroke="#6E80BF" stroke-width="1.69919"/>
+<path d="M172.468 50.39C172.468 55.6225 168.596 59.7356 163.972 59.7356C159.347 59.7356 155.476 55.6225 155.476 50.39C155.476 45.1575 159.347 41.0444 163.972 41.0444C168.596 41.0444 172.468 45.1575 172.468 50.39Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
+<path d="M172.468 93.1903C172.468 98.4228 168.596 102.536 163.972 102.536C159.347 102.536 155.476 98.4228 155.476 93.1903C155.476 87.9578 159.347 83.8447 163.972 83.8447C168.596 83.8447 172.468 87.9578 172.468 93.1903Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
+<path d="M26.3171 49.4691C26.3171 54.7016 22.4453 58.8147 17.8212 58.8147C13.197 58.8147 9.32518 54.7016 9.32518 49.4691C9.32518 44.2366 13.197 40.1235 17.8212 40.1235C22.4453 40.1235 26.3171 44.2366 26.3171 49.4691Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
+<path d="M26.3367 92.87C26.3367 98.1025 22.4648 102.216 17.8407 102.216C13.2166 102.216 9.34471 98.1025 9.34471 92.87C9.34471 87.6375 13.2166 83.5244 17.8407 83.5244C22.4648 83.5244 26.3367 87.6375 26.3367 92.87Z" fill="#6E80C0" stroke="#8397DE" stroke-width="1.69919"/>
+<path d="M105.329 70.7255L105.329 70.7256L93.111 77.9472L93.1106 77.9474C92.199 78.4868 91.0649 78.4871 90.1516 77.9472L90.1515 77.9471L77.9287 70.7256C76.537 69.903 76.0828 68.1043 76.9171 66.721L76.9172 66.7208L89.1402 46.4409L89.1402 46.4408C90.2706 44.5646 92.9907 44.5646 94.1211 46.4408L106.339 66.7207L106.339 66.7208C107.174 68.1058 106.719 69.9044 105.329 70.7255Z" fill="#5265AA" stroke="#5265AA" stroke-width="1.69919"/>
+<path d="M93.4911 93.863L93.4911 93.863C92.5828 95.1423 90.6834 95.1423 89.7751 93.863L77.2355 76.1985L90.7948 84.2098C90.7952 84.21 90.7955 84.2102 90.7959 84.2104C91.3117 84.5159 91.9534 84.5158 92.4693 84.2103C92.4696 84.2101 92.4699 84.2099 92.4702 84.2098L106.035 76.1981L93.4911 93.863Z" fill="#5265AA" stroke="#5265AA" stroke-width="1.69919"/>
+<circle cx="177" cy="32" r="32" fill="#9AA7D7"/>
+<g opacity="0.7">
+<line x1="195.064" y1="32.5152" x2="158.935" y2="32.5152" stroke="white" stroke-width="5.16129" stroke-linecap="round"/>
+<line x1="177.516" y1="50.0644" x2="177.516" y2="13.9353" stroke="white" stroke-width="5.16129" stroke-linecap="round"/>
+</g>
+</svg>
diff --git a/packages/website/public/images/instant/feature_3.svg b/packages/website/public/images/instant/feature_3.svg
new file mode 100644
index 000000000..83aa259c6
--- /dev/null
+++ b/packages/website/public/images/instant/feature_3.svg
@@ -0,0 +1,195 @@
+<svg width="312" height="238" viewBox="0 0 312 238" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0)">
+<path d="M4.54049 64.6748L115.492 0.617544C117.998 -0.826333 120.032 0.345114 120.032 3.24195V162.804C120.032 165.701 117.998 169.215 115.492 170.668L4.54049 234.716C2.03414 236.16 0 234.989 0 232.092V72.539C0 69.6421 2.03414 66.1278 4.54049 64.6748Z" fill="#363636"/>
+<path d="M4.54049 64.6748L115.492 0.617544C117.998 -0.826333 120.032 0.345114 120.032 3.24195V43.6342L0 112.931V72.539C0 69.6421 2.03414 66.1278 4.54049 64.6748Z" fill="#363636"/>
+<path d="M14.8197 76.8164L13.5393 77.552C13.4667 77.7064 12.9854 79.577 11.4053 80.4851V81.8745C12.4768 81.257 13.2124 80.3943 13.3668 79.9675L13.4394 79.9221V88.6126L14.8106 87.8226V76.8164H14.8197ZM24.0551 78.9414L22.7111 79.7133V72.2578L21.2037 73.1295L17.0627 83.3366V84.4354L21.4034 81.929V84.0176L22.7111 83.2639V81.1753L24.0551 80.4034V78.9414ZM18.7245 82.0198L21.2037 75.763L21.4034 75.1001V80.467L18.7245 82.0198ZM31.7104 71.84C31.7104 68.6526 30.5026 67.6174 28.4775 68.7797C26.4343 69.9603 25.2175 72.4031 25.2175 75.5905V76.8891C25.2175 80.1401 26.4525 81.2661 28.4957 80.0856C30.5208 78.9141 31.7194 76.3896 31.7194 73.1386V71.84H31.7104ZM30.2483 74.2465C30.2483 76.2352 29.6399 77.9606 28.4866 78.6326C27.3061 79.3137 26.6704 78.3057 26.6704 76.317V74.4826C26.6704 72.5393 27.297 70.9138 28.4775 70.2327C29.6399 69.5607 30.2574 70.4597 30.2574 72.4121V74.2465H30.2483ZM33.8353 76.9526C34.3529 76.653 34.7797 75.9265 34.7797 75.3181C34.7797 74.7278 34.3529 74.4917 33.8353 74.7914C33.3268 75.082 32.8909 75.7993 32.8909 76.4078C32.9 77.0162 33.3177 77.2614 33.8353 76.9526ZM42.3079 65.7195C42.3079 62.532 41.1001 61.4968 39.075 62.6592C37.0318 63.8397 35.815 66.2825 35.815 69.4699V70.7685C35.815 74.0195 37.05 75.1455 39.0932 73.965C41.1183 72.7935 42.317 70.269 42.317 67.018V65.7195H42.3079ZM40.8549 68.1259C40.8549 70.1146 40.2465 71.84 39.0932 72.512C37.9127 73.1931 37.277 72.1851 37.277 70.1964V68.362C37.277 66.4187 37.9036 64.7932 39.0841 64.1121C40.2465 63.4401 40.864 64.3391 40.864 66.2916V68.1259H40.8549ZM50.1811 61.1699C50.1811 57.9825 48.9733 56.9472 46.9483 58.1096C44.905 59.2901 43.6882 61.7329 43.6882 64.9203V66.2189C43.6882 69.4699 44.9232 70.5959 46.9664 69.4154C48.9915 68.244 50.1902 65.7195 50.1902 62.4685V61.1699H50.1811ZM48.7281 63.5763C48.7281 65.5651 48.1197 67.2905 46.9664 67.9625C45.7859 68.6435 45.1502 67.6355 45.1502 65.6468V63.8124C45.1502 61.8691 45.7768 60.2436 46.9573 59.5625C48.1197 58.8905 48.7372 59.7896 48.7372 61.742V63.5763H48.7281ZM62.0772 59.0812L57.0826 61.969L62.0409 50.6813V49.5553L55.2574 53.4692V54.9312L60.2519 52.0526L55.2937 63.3402V64.4663L62.0772 60.5524V59.0812ZM69.1059 56.4841L70.7768 55.5215L68.7517 52.1434C69.7869 51.0082 70.4226 49.637 70.4226 48.1205C70.4226 46.1862 69.4146 45.3054 67.1535 46.6131L63.8116 48.5382V59.5535L65.2919 58.6998V54.4863L67.2806 53.3421L69.1059 56.4841ZM65.2828 49.1466L67.1444 48.0751C68.5428 47.2669 68.9606 47.9752 68.9606 48.9832C68.9606 50.1274 68.443 51.1808 67.0536 51.9799L65.2828 53.0061V49.1466ZM73.2105 43.1078L71.5033 44.0885L74.4818 47.8753L71.4851 55.1129L73.2014 54.123L75.4353 48.62L75.508 48.5745L77.7419 51.4986L79.4582 50.5088L76.5069 46.7039L79.44 39.5117L77.7328 40.4925L75.508 46.041L75.4353 46.0864L73.2105 43.1078Z" fill="#363636"/>
+<path d="M10.724 199.291L109.716 142.145C110.833 141.5 111.732 142.027 111.732 143.307V160.443C111.732 161.732 110.833 163.294 109.716 163.939L10.724 221.086C9.60703 221.73 8.70801 221.204 8.70801 219.923V202.788C8.70801 201.498 9.61611 199.936 10.724 199.291Z" fill="#363636"/>
+<path opacity="0.2" d="M10.5881 121.159L109.435 64.0936C109.989 63.7758 110.443 64.0301 110.443 64.6748V78.6505C110.443 79.2952 109.989 80.0762 109.435 80.394L10.5881 137.468C10.0341 137.786 9.58008 137.532 9.58008 136.887V122.911C9.58008 122.266 10.0341 121.485 10.5881 121.159Z" fill="#363636"/>
+<path opacity="0.2" d="M9.7168 183.272L107.583 126.771" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path opacity="0.2" d="M9.7168 167.835L107.583 111.333" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path opacity="0.2" d="M9.7168 153.305L107.583 96.8032" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path d="M6.56588 66.4912L117.517 2.43395C120.024 0.990073 122.058 2.16152 122.058 5.05836V164.62C122.058 167.517 120.024 171.032 117.517 172.485L6.56588 236.533C4.05953 237.977 2.02539 236.805 2.02539 233.908V74.3554C2.02539 71.4585 4.05953 67.9442 6.56588 66.4912Z" fill="#424242"/>
+<path d="M85.7878 33.0822C85.7878 35.1708 85.1159 36.7237 83.9081 37.4229C82.7003 38.1222 82.0283 37.3503 82.0283 35.2526C82.0283 33.1549 82.7003 31.602 83.9081 30.9028C85.1159 30.2035 85.7878 30.9845 85.7878 33.0822ZM84.8888 32.2377C84.7254 31.5929 84.3894 31.4022 83.9081 31.6837C83.1816 32.1015 82.7911 33.1912 82.7911 34.8167C82.7911 35.0074 82.7911 35.1799 82.8093 35.3434L84.8888 32.2377ZM82.9183 36.1153C83.0908 36.7509 83.4177 36.9416 83.9081 36.6601C84.6346 36.2424 85.016 35.1527 85.016 33.5272C85.016 33.3365 85.016 33.1549 84.9978 32.9914L82.9183 36.1153Z" fill="#FF602E"/>
+<path d="M87.9219 34.1629C87.9219 33.6998 88.2397 33.1277 88.6393 32.9006C89.0388 32.6736 89.3567 32.8643 89.3567 33.3365C89.3567 33.7997 89.0388 34.3718 88.6393 34.5988C88.2397 34.8258 87.9219 34.626 87.9219 34.1629Z" fill="#FF602E"/>
+<path d="M93.4165 31.9291C92.3086 32.5738 91.5186 32.1289 91.5186 30.8485C91.5186 30.1129 91.7365 29.3138 92.2632 28.1423C92.3449 27.9425 93.3802 25.6905 93.4528 25.5452L94.3427 25.0366L92.9079 28.1332C92.7445 28.4965 92.7445 28.5056 92.7082 28.6054L92.7717 28.5964C92.9443 28.2513 93.3166 27.8608 93.6617 27.661C94.6243 27.1071 95.3326 27.543 95.3326 28.6781C95.3144 29.9131 94.5153 31.2934 93.4165 31.9291ZM94.5516 29.1594C94.5516 28.3966 94.0612 28.106 93.4165 28.4783C92.7717 28.8506 92.2814 29.7133 92.2814 30.4761C92.2814 31.2389 92.7717 31.5295 93.4165 31.1572C94.0612 30.7758 94.5516 29.9131 94.5516 29.1594Z" fill="#FF602E"/>
+<path d="M100.017 24.8641C100.017 26.9527 99.3453 28.5056 98.1376 29.2048C96.9298 29.904 96.2578 29.1321 96.2578 27.0344C96.2578 24.9367 96.9298 23.3839 98.1376 22.6846C99.3453 21.9945 100.017 22.7664 100.017 24.8641ZM99.1183 24.0195C98.9549 23.3748 98.6189 23.1841 98.1285 23.4656C97.402 23.8833 97.0115 24.973 97.0115 26.5985C97.0115 26.7892 97.0115 26.9618 97.0297 27.1252L99.1183 24.0195ZM97.1478 27.8971C97.3203 28.5328 97.6472 28.7235 98.1376 28.442C98.8641 28.0243 99.2455 26.9345 99.2455 25.309C99.2455 25.1183 99.2455 24.9367 99.2273 24.7733L97.1478 27.8971Z" fill="#FF602E"/>
+<path d="M85.7878 44.3337C85.7878 46.4223 85.1159 47.9751 83.9081 48.6744C82.7003 49.3736 82.0283 48.6017 82.0283 46.504C82.0283 44.4063 82.7003 42.8535 83.9081 42.1542C85.1159 41.455 85.7878 42.236 85.7878 44.3337ZM84.8888 43.4801C84.7254 42.8353 84.3894 42.6446 83.9081 42.9261C83.1816 43.3438 82.7911 44.4336 82.7911 46.0591C82.7911 46.2498 82.7911 46.4223 82.8093 46.5858L84.8888 43.4801ZM82.9183 47.3576C83.0908 47.9933 83.4177 48.184 83.9081 47.9025C84.6346 47.4848 85.016 46.3951 85.016 44.7696C85.016 44.5789 85.016 44.3972 84.9978 44.2338L82.9183 47.3576Z" fill="#FF602E"/>
+<path d="M87.9219 45.4051C87.9219 44.942 88.2397 44.3699 88.6393 44.1428C89.0388 43.9158 89.3567 44.1065 89.3567 44.5787C89.3567 45.0419 89.0388 45.614 88.6393 45.841C88.2397 46.068 87.9219 45.8682 87.9219 45.4051Z" fill="#FF602E"/>
+<path d="M91.5273 42.4452L92.272 42.0093C92.3356 42.5814 92.7805 42.7448 93.3799 42.3997C94.0428 42.0183 94.4877 41.2283 94.4877 40.4201C94.4877 39.6119 94.0428 39.3213 93.3799 39.7027C92.9258 39.966 92.5535 40.4201 92.3446 40.965L91.6 41.3918L91.8633 37.6958L94.9145 35.9341V36.715L92.4808 38.1226L92.3356 40.1386L92.3991 40.1023C92.6534 39.5756 93.0439 39.1578 93.5252 38.8763C94.5241 38.2951 95.2233 38.7492 95.2233 39.9751C95.2233 41.2555 94.4605 42.5632 93.3345 43.217C92.3083 43.8073 91.5727 43.4985 91.5273 42.4452Z" fill="#FF602E"/>
+<path d="M98.1284 33.9542C99.2363 33.3094 100.026 33.7544 100.026 35.0348C100.026 35.7522 99.8084 36.5514 99.2726 37.75C99.1818 37.9589 98.1466 40.211 98.083 40.3472L97.1931 40.8557L98.6278 37.7591C98.755 37.4776 98.7913 37.3868 98.8276 37.296L98.7641 37.3051C98.5915 37.6502 98.2283 38.0316 97.8923 38.2313C96.9297 38.7853 96.2305 38.3585 96.2305 37.2052C96.2305 35.9611 97.0296 34.5899 98.1284 33.9542ZM96.9933 36.7239C96.9933 37.4867 97.4836 37.7773 98.1284 37.405C98.7731 37.0326 99.2635 36.17 99.2635 35.4071C99.2635 34.6443 98.7731 34.3538 98.1284 34.7261C97.4836 35.0984 96.9933 35.9611 96.9933 36.7239Z" fill="#FF602E"/>
+<path d="M85.7878 56.5112C85.7878 58.5998 85.1159 60.1527 83.9081 60.8519C82.7003 61.5511 82.0283 60.7793 82.0283 58.6816C82.0283 56.5838 82.7003 55.031 83.9081 54.3318C85.1159 53.6325 85.7878 54.4226 85.7878 56.5112ZM84.8888 55.6667C84.7254 55.0219 84.3894 54.8312 83.9081 55.1127C83.1816 55.5304 82.7911 56.6202 82.7911 58.2457C82.7911 58.4364 82.7911 58.6089 82.8093 58.7724L84.8888 55.6667ZM82.9183 59.5442C83.0908 60.1799 83.4177 60.3706 83.9081 60.0891C84.6346 59.6714 85.016 58.5817 85.016 56.9562C85.016 56.7655 85.016 56.5838 84.9978 56.4204L82.9183 59.5442Z" fill="#FF602E"/>
+<path d="M87.9219 57.5916C87.9219 57.1285 88.2397 56.5564 88.6393 56.3294C89.0388 56.1023 89.3567 56.293 89.3567 56.7652C89.3567 57.2284 89.0388 57.8005 88.6393 58.0275C88.2397 58.2545 87.9219 58.0547 87.9219 57.5916Z" fill="#FF602E"/>
+<path d="M91.5273 54.6317L92.272 54.1958C92.3356 54.7679 92.7805 54.9313 93.3799 54.5863C94.0428 54.2049 94.4877 53.4148 94.4877 52.6066C94.4877 51.7984 94.0428 51.5078 93.3799 51.8892C92.9258 52.1526 92.5535 52.6066 92.3446 53.1515L91.6091 53.5783L91.8724 49.8823L94.9236 48.1206V48.9016L92.4899 50.3091L92.3446 52.3251L92.4082 52.2888C92.6625 51.7621 93.0529 51.3444 93.5342 51.0628C94.5331 50.4817 95.2324 50.9357 95.2324 52.1616C95.2324 53.4421 94.4696 54.7497 93.3435 55.4036C92.3083 55.9938 91.5727 55.6851 91.5273 54.6317Z" fill="#FF602E"/>
+<path d="M96.1768 51.9617C96.1768 51.1898 96.6126 50.3089 97.2937 49.7277V49.6551C96.7398 49.8004 96.3947 49.4644 96.3947 48.7924C96.3947 47.8116 97.1212 46.7038 98.1473 46.1135C99.1735 45.5232 99.9 45.7957 99.9 46.7673C99.9 47.4393 99.5549 48.1658 98.9919 48.6653V48.7379C99.6639 48.5109 100.118 48.9014 100.118 49.6732C100.118 50.7448 99.3097 51.9526 98.1473 52.6246C96.985 53.3056 96.1768 53.0332 96.1768 51.9617ZM99.3279 50.0728C99.3279 49.3917 98.8466 49.201 98.1564 49.6097C97.4663 50.0183 96.985 50.7539 96.985 51.435C96.985 52.116 97.4663 52.3067 98.1564 51.8981C98.8466 51.4894 99.3279 50.7448 99.3279 50.0728ZM99.1372 47.294C99.1372 46.6856 98.7376 46.5131 98.1473 46.8491C97.548 47.1941 97.1575 47.8298 97.1575 48.4291C97.1575 49.0376 97.548 49.2192 98.1473 48.8741C98.7376 48.5381 99.1372 47.9025 99.1372 47.294Z" fill="#FF602E"/>
+<path d="M85.7878 68.2712C85.7878 70.3598 85.1159 71.9126 83.9081 72.6119C82.7003 73.3111 82.0283 72.5392 82.0283 70.4415C82.0283 68.3438 82.7003 66.791 83.9081 66.0917C85.1159 65.3925 85.7878 66.1735 85.7878 68.2712ZM84.8888 67.4266C84.7254 66.7819 84.3894 66.5912 83.9081 66.8727C83.1816 67.2904 82.7911 68.3801 82.7911 70.0056C82.7911 70.1963 82.7911 70.3689 82.8093 70.5323L84.8888 67.4266ZM82.9183 71.2951C83.0908 71.9308 83.4177 72.1215 83.9081 71.84C84.6346 71.4223 85.016 70.3326 85.016 68.7071C85.016 68.5164 85.016 68.3347 84.9978 68.1713L82.9183 71.2951Z" fill="#FF602E"/>
+<path d="M87.9219 69.3519C87.9219 68.8887 88.2397 68.3166 88.6393 68.0896C89.0388 67.8626 89.3567 68.0533 89.3567 68.5255C89.3567 68.9886 89.0388 69.5607 88.6393 69.7878C88.2397 70.0148 87.9219 69.815 87.9219 69.3519Z" fill="#FF602E"/>
+<path d="M91.5273 66.3822L92.272 65.9463C92.3356 66.5184 92.7805 66.6818 93.3799 66.3368C94.0428 65.9554 94.4877 65.1653 94.4877 64.3571C94.4877 63.5489 94.0428 63.2583 93.3799 63.6397C92.9258 63.9031 92.5535 64.3571 92.3446 64.902L91.6 65.3288L91.8633 61.6328L94.9145 59.8711V60.6521L92.4808 62.0596L92.3356 64.0756L92.3991 64.0393C92.6534 63.5126 93.0439 63.0948 93.5252 62.8133C94.5241 62.2321 95.2233 62.6862 95.2233 63.9121C95.2233 65.1926 94.4605 66.5002 93.3345 67.154C92.3083 67.7443 91.5727 67.4356 91.5273 66.3822Z" fill="#FF602E"/>
+<path d="M99.2097 58.2366V58.173L96.3311 59.8348V59.0629L100.009 56.938V57.728L97.6206 64.5569L96.7942 65.0291L99.2097 58.2366Z" fill="#FF602E"/>
+<path d="M85.7878 79.5226C85.7878 81.6113 85.1159 83.1641 83.9081 83.8633C82.7003 84.5626 82.0283 83.7907 82.0283 81.693C82.0283 79.5953 82.7003 78.0424 83.9081 77.3432C85.1159 76.644 85.7878 77.4249 85.7878 79.5226ZM84.8888 78.669C84.7254 78.0243 84.3894 77.8336 83.9081 78.1151C83.1816 78.5328 82.7911 79.6225 82.7911 81.248C82.7911 81.4387 82.7911 81.6113 82.8093 81.7747L84.8888 78.669ZM82.9183 82.5466C83.0908 83.1823 83.4177 83.373 83.9081 83.0915C84.6346 82.6737 85.016 81.584 85.016 79.9585C85.016 79.7678 85.016 79.5862 84.9978 79.4227L82.9183 82.5466Z" fill="#FF602E"/>
+<path d="M87.9219 80.5936C87.9219 80.1304 88.2397 79.5583 88.6393 79.3313C89.0388 79.1043 89.3567 79.295 89.3567 79.7672C89.3567 80.2303 89.0388 80.8024 88.6393 81.0295C88.2397 81.2565 87.9219 81.0567 87.9219 80.5936Z" fill="#FF602E"/>
+<path d="M91.5273 77.6336L92.272 77.1977C92.3356 77.7698 92.7805 77.9333 93.3799 77.5882C94.0428 77.2068 94.4877 76.4168 94.4877 75.6086C94.4877 74.8004 94.0428 74.5098 93.3799 74.8912C92.9258 75.1545 92.5535 75.6086 92.3446 76.1534L91.6 76.5802L91.8633 72.8843L94.9145 71.1226V71.9035L92.4808 73.3111L92.3356 75.3271L92.3991 75.2907C92.6534 74.764 93.0439 74.3463 93.5252 74.0648C94.5241 73.4836 95.2233 73.9377 95.2233 75.1636C95.2233 76.444 94.4605 77.7517 93.3345 78.4055C92.3083 78.9958 91.5727 78.687 91.5273 77.6336Z" fill="#FF602E"/>
+<path d="M98.1645 75.6176C97.0566 76.2623 96.2666 75.8174 96.2666 74.5369C96.2666 73.8014 96.4845 73.0022 97.0112 71.8308C97.1021 71.631 98.1282 69.3789 98.2008 69.2336L99.0908 68.7251L97.656 71.8217C97.4925 72.185 97.4925 72.194 97.4562 72.2939L97.5198 72.2848C97.6923 71.9398 98.0646 71.5493 98.4097 71.3495C99.3723 70.7956 100.081 71.2315 100.081 72.3666C100.053 73.6107 99.2542 74.991 98.1645 75.6176ZM99.2906 72.8479C99.2906 72.0851 98.8002 71.7945 98.1554 72.1668C97.5107 72.5391 97.0203 73.4018 97.0203 74.1646C97.0203 74.9274 97.5107 75.218 98.1554 74.8457C98.8002 74.4734 99.2906 73.6107 99.2906 72.8479Z" fill="#FF602E"/>
+<path d="M85.7878 91.6999C85.7878 93.7885 85.1159 95.3414 83.9081 96.0406C82.7003 96.7398 82.0283 95.9679 82.0283 93.8702C82.0283 91.7725 82.7003 90.2197 83.9081 89.5204C85.1159 88.8212 85.7878 89.6022 85.7878 91.6999ZM84.8888 90.8553C84.7254 90.2106 84.3894 90.0199 83.9081 90.3014C83.1816 90.7191 82.7911 91.8088 82.7911 93.4343C82.7911 93.625 82.7911 93.7976 82.8093 93.961L84.8888 90.8553ZM82.9183 94.7329C83.0908 95.3686 83.4177 95.5593 83.9081 95.2778C84.6346 94.8601 85.016 93.7703 85.016 92.1448C85.016 91.9541 85.016 91.7725 84.9978 91.6091L82.9183 94.7329Z" fill="#FF602E"/>
+<path d="M87.9219 92.7806C87.9219 92.3174 88.2397 91.7453 88.6393 91.5183C89.0388 91.2913 89.3567 91.482 89.3567 91.9542C89.3567 92.4173 89.0388 92.9894 88.6393 93.2165C88.2397 93.4435 87.9219 93.2437 87.9219 92.7806Z" fill="#FF602E"/>
+<path d="M91.5273 89.8202L92.272 89.3843C92.3356 89.9564 92.7805 90.1198 93.3799 89.7747C94.0428 89.3933 94.4877 88.6033 94.4877 87.7951C94.4877 86.9869 94.0428 86.6963 93.3799 87.0777C92.9258 87.341 92.5535 87.7951 92.3446 88.34L91.6 88.7668L91.8633 85.0708L94.9145 83.3091V84.09L92.4808 85.4976L92.3356 87.5136L92.3991 87.4773C92.6534 86.9506 93.0439 86.5328 93.5252 86.2513C94.5241 85.6701 95.2233 86.1242 95.2233 87.3501C95.2233 88.6305 94.4605 89.9382 93.3345 90.592C92.3083 91.1823 91.5727 90.8736 91.5273 89.8202Z" fill="#FF602E"/>
+<path d="M96.2666 87.0775L97.0112 86.6416C97.0748 87.2137 97.5198 87.3771 98.1191 87.0321C98.782 86.6507 99.227 85.8606 99.227 85.0524C99.227 84.2442 98.782 83.9536 98.1191 84.335C97.6651 84.5984 97.2928 85.0524 97.0839 85.5973L96.3392 86.0241L96.6026 82.3281L99.6538 80.5664V81.3474L97.2201 82.7549L97.0748 84.7709L97.1384 84.7346C97.3926 84.2079 97.7831 83.7902 98.2644 83.5086C99.2633 82.9275 99.9626 83.3815 99.9626 84.6074C99.9626 85.8879 99.1998 87.1955 98.0737 87.8494C97.0476 88.4396 96.312 88.1309 96.2666 87.0775Z" fill="#FF602E"/>
+<path d="M85.7878 114.238C85.7878 116.327 85.1159 117.88 83.9081 118.579C82.7003 119.278 82.0283 118.507 82.0283 116.409C82.0283 114.311 82.7003 112.758 83.9081 112.059C85.1159 111.36 85.7878 112.141 85.7878 114.238ZM84.8888 113.394C84.7254 112.749 84.3894 112.558 83.9081 112.84C83.1816 113.258 82.7911 114.347 82.7911 115.973C82.7911 116.164 82.7911 116.336 82.8093 116.5L84.8888 113.394ZM82.9183 117.271C83.0908 117.907 83.4177 118.098 83.9081 117.816C84.6346 117.399 85.016 116.309 85.016 114.683C85.016 114.493 85.016 114.311 84.9978 114.148L82.9183 117.271Z" fill="#23C49E"/>
+<path d="M87.9219 115.319C87.9219 114.856 88.2397 114.284 88.6393 114.057C89.0388 113.83 89.3567 114.021 89.3567 114.493C89.3567 114.956 89.0388 115.528 88.6393 115.755C88.2397 115.982 87.9219 115.782 87.9219 115.319Z" fill="#23C49E"/>
+<path d="M91.5273 112.349L92.272 111.914C92.3356 112.486 92.7805 112.649 93.3799 112.304C94.0428 111.923 94.4877 111.133 94.4877 110.324C94.4877 109.516 94.0428 109.226 93.3799 109.607C92.9258 109.87 92.5535 110.324 92.3446 110.869L91.6 111.296L91.8633 107.6L94.9145 105.838V106.619L92.4808 108.027L92.3356 110.043L92.3991 110.007C92.6534 109.48 93.0439 109.062 93.5252 108.781C94.5241 108.199 95.2233 108.653 95.2233 109.879C95.2233 111.16 94.4605 112.467 93.3345 113.121C92.3083 113.721 91.5727 113.412 91.5273 112.349Z" fill="#23C49E"/>
+<path d="M98.7006 108.617L96.2578 110.025V109.307L98.0377 104.04L98.8277 103.586L97.0842 108.735V108.799L98.7278 107.854V106.129L99.4271 105.72V107.446L100.226 106.983V107.736L99.4362 108.19V109.471L98.7188 109.889V108.617H98.7006Z" fill="#23C49E"/>
+<path d="M85.7878 125.49C85.7878 127.579 85.1159 129.132 83.9081 129.831C82.7003 130.53 82.0283 129.758 82.0283 127.661C82.0283 125.563 82.7003 124.01 83.9081 123.311C85.1159 122.612 85.7878 123.393 85.7878 125.49ZM84.8888 124.646C84.7254 124.001 84.3894 123.81 83.9081 124.092C83.1816 124.51 82.7911 125.599 82.7911 127.225C82.7911 127.416 82.7911 127.588 82.8093 127.752L84.8888 124.646ZM82.9183 128.514C83.0908 129.15 83.4177 129.341 83.9081 129.059C84.6346 128.642 85.016 127.552 85.016 125.926C85.016 125.736 85.016 125.554 84.9978 125.391L82.9183 128.514Z" fill="#23C49E"/>
+<path d="M87.9219 126.571C87.9219 126.108 88.2397 125.536 88.6393 125.309C89.0388 125.082 89.3567 125.273 89.3567 125.745C89.3567 126.208 89.0388 126.78 88.6393 127.007C88.2397 127.234 87.9219 127.025 87.9219 126.571Z" fill="#23C49E"/>
+<path d="M91.5273 123.601L92.272 123.166C92.3356 123.738 92.7805 123.901 93.3799 123.556C94.0428 123.175 94.4877 122.385 94.4877 121.576C94.4877 120.768 94.0428 120.478 93.3799 120.859C92.9258 121.122 92.5535 121.576 92.3446 122.121L91.6 122.548L91.8633 118.852L94.9145 117.09V117.871L92.4808 119.279L92.3356 121.295L92.3991 121.259C92.6534 120.732 93.0439 120.314 93.5252 120.033C94.5241 119.451 95.2233 119.905 95.2233 121.131C95.2233 122.412 94.4605 123.719 93.3345 124.373C92.3083 124.964 91.5727 124.655 91.5273 123.601Z" fill="#23C49E"/>
+<path d="M97.4751 118.289L98.0745 117.944C98.6557 117.608 99.0643 116.945 99.0643 116.327C99.0643 115.719 98.6738 115.546 98.0836 115.892C97.4933 116.228 97.1119 116.845 97.0574 117.517L96.3309 117.935C96.3854 116.8 97.0665 115.719 98.1017 115.12C99.1097 114.538 99.809 114.802 99.809 115.764C99.809 116.509 99.4639 117.254 98.8736 117.744V117.817C99.6001 117.508 100.027 117.835 100.027 118.679C100.027 119.76 99.2369 120.968 98.1199 121.613C97.0211 122.248 96.2674 121.967 96.2129 120.886L96.9394 120.468C96.9939 121.077 97.4479 121.222 98.0927 120.841C98.801 120.432 99.2369 119.76 99.2369 119.097C99.2369 118.416 98.7828 118.244 98.0745 118.661L97.4479 119.024V118.289H97.4751Z" fill="#23C49E"/>
+<path d="M85.7878 137.677C85.7878 139.766 85.1159 141.319 83.9081 142.018C82.7003 142.717 82.0283 141.945 82.0283 139.848C82.0283 137.75 82.7003 136.197 83.9081 135.498C85.1159 134.799 85.7878 135.58 85.7878 137.677ZM84.8888 136.824C84.7254 136.179 84.3894 135.988 83.9081 136.27C83.1816 136.688 82.7911 137.777 82.7911 139.403C82.7911 139.593 82.7911 139.766 82.8093 139.929L84.8888 136.824ZM82.9183 140.701C83.0908 141.337 83.4177 141.528 83.9081 141.246C84.6346 140.829 85.016 139.739 85.016 138.113C85.016 137.923 85.016 137.741 84.9978 137.578L82.9183 140.701Z" fill="#23C49E"/>
+<path d="M87.9219 138.748C87.9219 138.285 88.2397 137.713 88.6393 137.486C89.0388 137.259 89.3567 137.45 89.3567 137.922C89.3567 138.385 89.0388 138.957 88.6393 139.184C88.2397 139.411 87.9219 139.211 87.9219 138.748Z" fill="#23C49E"/>
+<path d="M91.5273 135.788L92.272 135.353C92.3356 135.925 92.7805 136.088 93.3799 135.743C94.0428 135.362 94.4877 134.572 94.4877 133.763C94.4877 132.955 94.0428 132.665 93.3799 133.046C92.9258 133.309 92.5535 133.763 92.3446 134.308L91.6 134.735L91.8633 131.039L94.9145 129.277V130.058L92.4808 131.466L92.3356 133.482L92.3991 133.446C92.6534 132.919 93.0439 132.501 93.5252 132.22C94.5241 131.638 95.2233 132.092 95.2233 133.318C95.2233 134.599 94.4605 135.906 93.3345 136.56C92.3083 137.151 91.5727 136.842 91.5273 135.788Z" fill="#23C49E"/>
+<path d="M98.1016 127.307C99.1277 126.716 99.8269 127.025 99.8269 128.078C99.8269 128.732 99.5545 129.432 98.6737 131.003L97.4659 133.182V133.255L99.9087 131.847V132.637L96.3762 134.68V134.063L98.1833 130.757C98.8825 129.477 99.0551 129.05 99.0551 128.578C99.0551 127.933 98.6646 127.752 98.0743 128.088C97.475 128.433 97.0754 129.123 97.0754 129.822V129.849L96.3398 130.276V130.249C96.3489 129.123 97.0754 127.906 98.1016 127.307Z" fill="#23C49E"/>
+<path d="M85.7878 149.428C85.7878 151.517 85.1159 153.069 83.9081 153.769C82.7003 154.468 82.0283 153.696 82.0283 151.598C82.0283 149.501 82.7003 147.948 83.9081 147.248C85.1159 146.549 85.7878 147.33 85.7878 149.428ZM84.8888 148.583C84.7254 147.939 84.3894 147.748 83.9081 148.029C83.1816 148.447 82.7911 149.537 82.7911 151.162C82.7911 151.353 82.7911 151.526 82.8093 151.689L84.8888 148.583ZM82.9183 152.461C83.0908 153.097 83.4177 153.287 83.9081 153.006C84.6346 152.588 85.016 151.498 85.016 149.873C85.016 149.682 85.016 149.501 84.9978 149.337L82.9183 152.461Z" fill="#23C49E"/>
+<path d="M87.9219 150.509C87.9219 150.045 88.2397 149.473 88.6393 149.246C89.0388 149.019 89.3567 149.21 89.3567 149.682C89.3567 150.145 89.0388 150.717 88.6393 150.944C88.2397 151.172 87.9219 150.972 87.9219 150.509Z" fill="#23C49E"/>
+<path d="M91.5273 147.539L92.272 147.103C92.3356 147.675 92.7805 147.839 93.3799 147.493C94.0428 147.112 94.4877 146.322 94.4877 145.514C94.4877 144.706 94.0428 144.415 93.3799 144.796C92.9258 145.06 92.5535 145.514 92.3446 146.059L91.6 146.486L91.8633 142.79L94.9145 141.028V141.809L92.4808 143.216L92.3356 145.232L92.3991 145.196C92.6534 144.669 93.0439 144.252 93.5252 143.97C94.5241 143.389 95.2233 143.843 95.2233 145.069C95.2233 146.349 94.4605 147.657 93.3345 148.311C92.3083 148.91 91.5727 148.601 91.5273 147.539Z" fill="#23C49E"/>
+<path d="M100.19 143.462V144.224L96.3938 146.413V145.65L97.9467 144.751V140.247L97.8831 140.283L96.3848 142.281V141.373L97.9467 139.284L98.7095 138.839V144.315L100.19 143.462Z" fill="#23C49E"/>
+<path d="M85.7878 160.678C85.7878 162.767 85.1159 164.32 83.9081 165.019C82.7003 165.718 82.0283 164.946 82.0283 162.849C82.0283 160.751 82.7003 159.198 83.9081 158.499C85.1159 157.8 85.7878 158.581 85.7878 160.678ZM84.8888 159.825C84.7254 159.18 84.3894 158.989 83.9081 159.271C83.1816 159.689 82.7911 160.778 82.7911 162.404C82.7911 162.594 82.7911 162.767 82.8093 162.93L84.8888 159.825ZM82.9183 163.702C83.0908 164.338 83.4177 164.529 83.9081 164.247C84.6346 163.829 85.016 162.74 85.016 161.114C85.016 160.924 85.016 160.742 84.9978 160.579L82.9183 163.702Z" fill="#23C49E"/>
+<path d="M87.9219 161.75C87.9219 161.287 88.2397 160.715 88.6393 160.488C89.0388 160.261 89.3567 160.451 89.3567 160.923C89.3567 161.387 89.0388 161.959 88.6393 162.186C88.2397 162.413 87.9219 162.213 87.9219 161.75Z" fill="#23C49E"/>
+<path d="M91.5273 158.79L92.272 158.354C92.3356 158.926 92.7805 159.09 93.3799 158.744C94.0428 158.363 94.4877 157.573 94.4877 156.765C94.4877 155.957 94.0428 155.666 93.3799 156.047C92.9258 156.311 92.5535 156.765 92.3446 157.31L91.6 157.736L91.8633 154.041L94.9145 152.279V153.06L92.4808 154.467L92.3356 156.483L92.3991 156.447C92.6534 155.92 93.0439 155.503 93.5252 155.221C94.5241 154.64 95.2233 155.094 95.2233 156.32C95.2233 157.6 94.4605 158.908 93.3345 159.562C92.3083 160.152 91.5727 159.843 91.5273 158.79Z" fill="#23C49E"/>
+<path d="M100.017 152.46C100.017 154.549 99.3453 156.102 98.1376 156.801C96.9298 157.5 96.2578 156.728 96.2578 154.631C96.2578 152.533 96.9298 150.98 98.1376 150.281C99.3453 149.591 100.017 150.363 100.017 152.46ZM99.1183 151.607C98.9549 150.962 98.6189 150.771 98.1285 151.053C97.402 151.47 97.0115 152.56 97.0115 154.186C97.0115 154.376 97.0115 154.549 97.0297 154.712L99.1183 151.607ZM97.1478 155.484C97.3203 156.12 97.6472 156.311 98.1376 156.029C98.8641 155.611 99.2455 154.522 99.2455 152.896C99.2455 152.705 99.2455 152.524 99.2273 152.36L97.1478 155.484Z" fill="#23C49E"/>
+<path d="M85.7878 172.856C85.7878 174.945 85.1159 176.498 83.9081 177.197C82.7003 177.896 82.0283 177.124 82.0283 175.027C82.0283 172.929 82.7003 171.376 83.9081 170.677C85.1159 169.978 85.7878 170.768 85.7878 172.856ZM84.8888 172.012C84.7254 171.367 84.3894 171.176 83.9081 171.458C83.1816 171.876 82.7911 172.965 82.7911 174.591C82.7911 174.782 82.7911 174.954 82.8093 175.118L84.8888 172.012ZM82.9183 175.889C83.0908 176.525 83.4177 176.716 83.9081 176.434C84.6346 176.017 85.016 174.927 85.016 173.301C85.016 173.111 85.016 172.929 84.9978 172.766L82.9183 175.889Z" fill="#23C49E"/>
+<path d="M87.9219 173.937C87.9219 173.474 88.2397 172.902 88.6393 172.675C89.0388 172.448 89.3567 172.638 89.3567 173.11C89.3567 173.574 89.0388 174.146 88.6393 174.373C88.2397 174.6 87.9219 174.4 87.9219 173.937Z" fill="#23C49E"/>
+<path d="M93.9613 169.978L91.5186 171.385V170.668L93.2984 165.401L94.0885 164.947L92.3449 170.096V170.159L93.9886 169.215V167.489L94.6878 167.081V168.806L95.4869 168.343V169.097L94.6969 169.551V170.831L93.9704 171.249V169.978H93.9613Z" fill="#23C49E"/>
+<path d="M98.1284 162.486C99.2363 161.841 100.026 162.286 100.026 163.567C100.026 164.284 99.8084 165.083 99.2726 166.282C99.1818 166.491 98.1466 168.743 98.083 168.879L97.1931 169.387L98.6278 166.291C98.755 166.009 98.7913 165.919 98.8276 165.828L98.7641 165.837C98.5915 166.182 98.2283 166.563 97.8923 166.763C96.9297 167.317 96.2305 166.89 96.2305 165.737C96.2305 164.493 97.0296 163.113 98.1284 162.486ZM96.9933 165.256C96.9933 166.018 97.4836 166.309 98.1284 165.937C98.7731 165.564 99.2635 164.702 99.2635 163.939C99.2635 163.176 98.7731 162.885 98.1284 163.258C97.4836 163.63 96.9933 164.493 96.9933 165.256Z" fill="#23C49E"/>
+<g opacity="0.6">
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 70.1598V70.9226L21.8489 73.1111V72.3483L23.4018 71.4493V66.9452L23.3382 66.9815L21.8398 68.9793V68.0712L23.4018 65.9826L24.1646 65.5376V71.0134L25.6448 70.1598Z" fill="white"/>
+<path opacity="0.6" d="M28.9047 67.7628L26.4619 69.1704V68.453L28.2418 63.186L29.0318 62.7319L27.2883 67.8809V67.9444L28.9229 67V65.2746L29.6221 64.866V66.5914L30.4212 66.1282V66.8819L29.6312 67.336V68.6164L28.9047 69.0341V67.7628Z" fill="white"/>
+<path opacity="0.6" d="M34.9617 62.4232C34.9617 64.5118 34.2897 66.0646 33.0819 66.7639C31.8741 67.4631 31.2021 66.6912 31.2021 64.5935C31.2021 62.4958 31.8741 60.943 33.0819 60.2437C34.2897 59.5536 34.9617 60.3255 34.9617 62.4232ZM34.0627 61.5786C33.8992 60.9339 33.5632 60.7432 33.0819 61.0247C32.3554 61.4424 31.965 62.5321 31.965 64.1576C31.965 64.3483 31.965 64.5209 31.9831 64.6843L34.0627 61.5786ZM32.0921 65.4562C32.2555 66.0919 32.5915 66.2826 33.0819 66.0011C33.8084 65.5833 34.1898 64.4936 34.1898 62.8681C34.1898 62.6774 34.1898 62.4958 34.1716 62.3324L32.0921 65.4562Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 63.5037C37.1045 63.0406 37.4223 62.4685 37.8219 62.2415C38.2215 62.0144 38.5393 62.2051 38.5393 62.6774C38.5393 63.1405 38.2215 63.7126 37.8219 63.9396C37.4223 64.1666 37.1045 63.9669 37.1045 63.5037Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 56.9476C44.4509 59.0362 43.7789 60.589 42.5712 61.2883C41.3634 61.9875 40.6914 61.2156 40.6914 59.1179C40.6914 57.0202 41.3634 55.4674 42.5712 54.7681C43.7789 54.078 44.4509 54.8499 44.4509 56.9476ZM43.5519 56.103C43.3885 55.4583 43.0525 55.2676 42.5712 55.5491C41.8447 55.9668 41.4542 57.0565 41.4542 58.682C41.4542 58.8727 41.4542 59.0453 41.4724 59.2087L43.5519 56.103ZM41.5813 59.9806C41.7539 60.6163 42.0808 60.807 42.5712 60.5255C43.2976 60.1078 43.679 59.018 43.679 57.3925C43.679 57.2018 43.67 57.0202 43.6609 56.8568L41.5813 59.9806Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 54.2049C49.2009 56.2935 48.5289 57.8464 47.3212 58.5456C46.1134 59.2448 45.4414 58.473 45.4414 56.3753C45.4414 54.2775 46.1134 52.7247 47.3212 52.0255C48.5199 51.3353 49.2009 52.1072 49.2009 54.2049ZM48.3019 53.3604C48.1385 52.7156 47.8025 52.5249 47.3212 52.8064C46.5947 53.2241 46.2042 54.3139 46.2042 55.9394C46.2042 56.1301 46.2042 56.3026 46.2224 56.4661L48.3019 53.3604ZM46.3223 57.2379C46.4948 57.8736 46.8217 58.0643 47.3121 57.7828C48.0386 57.3651 48.42 56.2754 48.42 54.6499C48.42 54.4592 48.4109 54.2775 48.4018 54.1141L46.3223 57.2379Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M30.1213 78.8234V79.5862L26.3255 81.7747V81.0119L27.8783 80.1129V75.6087L27.8148 75.6451L26.3164 77.6429V76.7348L27.8783 74.6461L28.6411 74.2012V79.677L30.1213 78.8234Z" fill="white"/>
+<path opacity="0.6" d="M32.7815 71.686C33.8077 71.0958 34.5069 71.4045 34.5069 72.4579C34.5069 73.1117 34.2345 73.811 33.3536 75.382L32.1459 77.5614V77.6341L34.5887 76.2265V77.0166L31.0561 79.0598V78.4423L32.8633 75.1368C33.5625 73.8564 33.735 73.4296 33.735 72.9573C33.735 72.3126 33.3446 72.131 32.7452 72.467C32.1459 72.8121 31.7463 73.5022 31.7463 74.2014V74.2287L31.0107 74.6555V74.6283C31.0198 73.4931 31.7463 72.2763 32.7815 71.686Z" fill="white"/>
+<path opacity="0.6" d="M36.832 74.9095C36.832 74.4464 37.1499 73.8743 37.5494 73.6472C37.949 73.4202 38.2668 73.6109 38.2668 74.0831C38.2668 74.5462 37.9399 75.1183 37.5494 75.3454C37.1589 75.5724 36.832 75.3726 36.832 74.9095Z" fill="white"/>
+<path opacity="0.6" d="M44.1882 68.3527C44.1882 70.4413 43.5162 71.9942 42.3085 72.6934C41.1007 73.3927 40.4287 72.6208 40.4287 70.5231C40.4287 68.4254 41.1007 66.8725 42.3085 66.1733C43.5162 65.474 44.1882 66.255 44.1882 68.3527ZM43.2892 67.4991C43.1258 66.8543 42.7898 66.6636 42.3085 66.9452C41.582 67.3629 41.1915 68.4526 41.1915 70.0781C41.1915 70.2688 41.1915 70.4413 41.2097 70.6048L43.2892 67.4991ZM41.3186 71.3767C41.4912 72.0123 41.8181 72.203 42.3085 71.9215C43.035 71.5038 43.4164 70.4141 43.4164 68.7886C43.4164 68.5979 43.4073 68.4163 43.3982 68.2528L41.3186 71.3767Z" fill="white"/>
+<path opacity="0.6" d="M48.9275 65.6107C48.9275 67.6993 48.2555 69.2521 47.0477 69.9514C45.84 70.6506 45.168 69.8787 45.168 67.781C45.168 65.6833 45.84 64.1305 47.0477 63.4312C48.2555 62.7411 48.9275 63.513 48.9275 65.6107ZM48.0285 64.7661C47.865 64.1214 47.529 63.9307 47.0477 64.2122C46.3213 64.6299 45.9308 65.7196 45.9308 67.3451C45.9308 67.5358 45.9308 67.7084 45.9489 67.8718L48.0285 64.7661ZM46.0579 68.6437C46.2304 69.2794 46.5574 69.4701 47.0477 69.1886C47.7742 68.7708 48.1556 67.6811 48.1556 66.0556C48.1556 65.8649 48.1465 65.6833 48.1374 65.5199L46.0579 68.6437Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 93.5895V94.3523L21.8489 96.5408V95.778L23.4018 94.879V90.3748L23.3382 90.4112L21.8398 92.409V91.5009L23.4018 89.4123L24.1646 88.9673V94.4431L25.6448 93.5895Z" fill="white"/>
+<path opacity="0.6" d="M27.6705 89.6209L28.2698 89.2759C28.851 88.9399 29.2596 88.277 29.2596 87.6594C29.2596 87.051 28.8692 86.8785 28.2789 87.2236C27.6886 87.5686 27.3072 88.1771 27.2527 88.8491L26.5263 89.2668C26.5807 88.1317 27.2618 87.051 28.297 86.4517C29.305 85.8705 30.0043 86.1338 30.0043 87.0964C30.0043 87.8411 29.6592 88.5857 29.0689 89.0761V89.1487C29.7954 88.84 30.2222 89.1669 30.2222 90.0114C30.2222 91.0921 29.4322 92.2998 28.3152 92.9446C27.2164 93.5802 26.4627 93.2987 26.4082 92.2181L27.1347 91.8004C27.1892 92.4088 27.6432 92.5541 28.288 92.1727C28.9872 91.7641 29.4322 91.0921 29.4322 90.4291C29.4322 89.7481 28.9781 89.5755 28.2698 89.9933L27.6432 90.3565V89.6209H27.6705Z" fill="white"/>
+<path opacity="0.6" d="M33.0452 83.7187C34.0714 83.1285 34.7706 83.4372 34.7706 84.4906C34.7706 85.1444 34.4982 85.8437 33.6173 87.4147L32.4095 89.5941V89.6668L34.8523 88.2592V89.0493L31.3198 91.0925V90.475L33.1269 87.1695C33.8262 85.8891 33.9987 85.4623 33.9987 84.9901C33.9987 84.3453 33.6082 84.1637 33.0089 84.4997C32.4095 84.8448 32.01 85.5349 32.01 86.2342V86.2614L31.2744 86.6882V86.661C31.2926 85.5258 32.0191 84.309 33.0452 83.7187Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 86.9329C37.1045 86.4698 37.4223 85.8977 37.8219 85.6707C38.2215 85.4436 38.5393 85.6343 38.5393 86.1066C38.5393 86.5697 38.2215 87.1418 37.8219 87.3688C37.4223 87.5958 37.1045 87.3961 37.1045 86.9329Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 80.3766C44.4509 82.4652 43.7789 84.018 42.5712 84.7173C41.3634 85.4165 40.6914 84.6446 40.6914 82.5469C40.6914 80.4492 41.3634 78.8964 42.5712 78.1971C43.7789 77.507 44.4509 78.2879 44.4509 80.3766ZM43.5519 79.532C43.3885 78.8873 43.0525 78.6966 42.5712 78.9781C41.8447 79.3958 41.4542 80.4855 41.4542 82.111C41.4542 82.3017 41.4542 82.4743 41.4724 82.6377L43.5519 79.532ZM41.5813 83.4096C41.7539 84.0453 42.0808 84.236 42.5712 83.9545C43.2976 83.5367 43.679 82.447 43.679 80.8215C43.679 80.6308 43.67 80.4492 43.6609 80.2858L41.5813 83.4096Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 77.6434C49.2009 79.732 48.5289 81.2848 47.3212 81.9841C46.1134 82.6833 45.4414 81.9114 45.4414 79.8137C45.4414 77.716 46.1134 76.1632 47.3212 75.4639C48.5199 74.7738 49.2009 75.5457 49.2009 77.6434ZM48.3019 76.7898C48.1385 76.145 47.8025 75.9543 47.3212 76.2358C46.5947 76.6535 46.2042 77.7433 46.2042 79.3688C46.2042 79.5595 46.2042 79.732 46.2224 79.8955L48.3019 76.7898ZM46.3223 80.6673C46.4948 81.303 46.8217 81.4937 47.3121 81.2122C48.0386 80.7945 48.42 79.7048 48.42 78.0793C48.42 77.8886 48.4109 77.7069 48.4018 77.5435L46.3223 80.6673Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 105.349V106.112L21.8489 108.3V107.537L23.4018 106.638V102.134L23.3382 102.17L21.8398 104.168V103.26L23.4018 101.172L24.1646 100.727V106.202L25.6448 105.349Z" fill="white"/>
+<path opacity="0.6" d="M28.9047 102.952L26.4619 104.359V103.642L28.2418 98.3749L29.0318 97.9209L27.2883 103.07V103.133L28.9229 102.189V100.464L29.6221 100.055V101.78L30.4212 101.317V102.071L29.6312 102.525V103.805L28.9047 104.223V102.952Z" fill="white"/>
+<path opacity="0.6" d="M34.9617 97.6121C34.9617 99.7008 34.2897 101.254 33.0819 101.953C31.8741 102.652 31.2021 101.88 31.2021 99.7825C31.2021 97.6848 31.8741 96.1319 33.0819 95.4327C34.2897 94.7425 34.9617 95.5144 34.9617 97.6121ZM34.0627 96.7676C33.8992 96.1228 33.5632 95.9321 33.0819 96.2137C32.3554 96.6314 31.965 97.7211 31.965 99.3466C31.965 99.5373 31.965 99.7098 31.9831 99.8733L34.0627 96.7676ZM32.0921 100.645C32.2555 101.281 32.5915 101.472 33.0819 101.19C33.8084 100.772 34.1898 99.6826 34.1898 98.0571C34.1898 97.8664 34.1898 97.6848 34.1716 97.5213L32.0921 100.645Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 98.6927C37.1045 98.2296 37.4223 97.6575 37.8219 97.4304C38.2215 97.2034 38.5393 97.3941 38.5393 97.8663C38.5393 98.3294 38.2215 98.9016 37.8219 99.1286C37.4223 99.3556 37.1045 99.1558 37.1045 98.6927Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 92.1365C44.4509 94.2252 43.7789 95.778 42.5712 96.4772C41.3634 97.1765 40.6914 96.4046 40.6914 94.3069C40.6914 92.2092 41.3634 90.6563 42.5712 89.9571C43.7789 89.2669 44.4509 90.0388 44.4509 92.1365ZM43.5519 91.292C43.3885 90.6473 43.0525 90.4566 42.5712 90.7381C41.8447 91.1558 41.4542 92.2455 41.4542 93.871C41.4542 94.0617 41.4542 94.2342 41.4724 94.3977L43.5519 91.292ZM41.5813 95.1605C41.7539 95.7962 42.0808 95.9869 42.5712 95.7054C43.2976 95.2876 43.679 94.1979 43.679 92.5724C43.679 92.3817 43.67 92.2001 43.6609 92.0366L41.5813 95.1605Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 89.3939C49.2009 91.4825 48.5289 93.0353 47.3212 93.7346C46.1134 94.4338 45.4414 93.6619 45.4414 91.5642C45.4414 89.4665 46.1134 87.9137 47.3212 87.2144C48.5199 86.5243 49.2009 87.2962 49.2009 89.3939ZM48.3019 88.5493C48.1385 87.9046 47.8025 87.7139 47.3212 87.9954C46.5947 88.4131 46.2042 89.5028 46.2042 91.1283C46.2042 91.319 46.2042 91.4916 46.2224 91.655L48.3019 88.5493ZM46.3223 92.4269C46.4948 93.0626 46.8217 93.2533 47.3121 92.9718C48.0386 92.554 48.42 91.4643 48.42 89.8388C48.42 89.6481 48.4109 89.4665 48.4018 89.303L46.3223 92.4269Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M30.1213 114.012V114.775L26.3255 116.964V116.201L27.8783 115.302V110.798L27.8148 110.834L26.3164 112.832V111.924L27.8783 109.835L28.6411 109.39V114.866L30.1213 114.012Z" fill="white"/>
+<path opacity="0.6" d="M32.7815 106.875C33.8077 106.285 34.5069 106.593 34.5069 107.647C34.5069 108.301 34.2345 109 33.3536 110.571L32.1459 112.75V112.823L34.5887 111.415V112.206L31.0561 114.249V113.631L32.8633 110.326C33.5625 109.045 33.735 108.619 33.735 108.146C33.735 107.502 33.3446 107.32 32.7452 107.656C32.1459 108.001 31.7463 108.691 31.7463 109.39V109.418L31.0107 109.844V109.817C31.0198 108.682 31.7463 107.465 32.7815 106.875Z" fill="white"/>
+<path opacity="0.6" d="M36.832 110.089C36.832 109.626 37.1499 109.054 37.5494 108.827C37.949 108.6 38.2668 108.791 38.2668 109.263C38.2668 109.726 37.9399 110.298 37.5494 110.525C37.1589 110.752 36.832 110.552 36.832 110.089Z" fill="white"/>
+<path opacity="0.6" d="M44.1882 103.533C44.1882 105.621 43.5162 107.174 42.3085 107.874C41.1007 108.573 40.4287 107.801 40.4287 105.703C40.4287 103.605 41.1007 102.053 42.3085 101.353C43.5162 100.663 44.1882 101.444 44.1882 103.533ZM43.2892 102.688C43.1258 102.044 42.7898 101.853 42.3085 102.134C41.582 102.552 41.1915 103.642 41.1915 105.267C41.1915 105.458 41.1915 105.631 41.2097 105.794L43.2892 102.688ZM41.3186 106.566C41.4912 107.202 41.8181 107.392 42.3085 107.111C43.035 106.693 43.4164 105.603 43.4164 103.978C43.4164 103.787 43.4073 103.605 43.3982 103.442L41.3186 106.566Z" fill="white"/>
+<path opacity="0.6" d="M48.9275 100.8C48.9275 102.888 48.2555 104.441 47.0477 105.14C45.84 105.84 45.168 105.068 45.168 102.97C45.168 100.872 45.84 99.3194 47.0477 98.6202C48.2555 97.93 48.9275 98.7019 48.9275 100.8ZM48.0285 99.9551C47.865 99.3103 47.529 99.1196 47.0477 99.4012C46.3213 99.8189 45.9308 100.909 45.9308 102.534C45.9308 102.725 45.9308 102.897 45.9489 103.061L48.0285 99.9551ZM46.0579 103.824C46.2304 104.459 46.5574 104.65 47.0477 104.368C47.7742 103.951 48.1556 102.861 48.1556 101.236C48.1556 101.045 48.1465 100.863 48.1374 100.7L46.0579 103.824Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 128.777V129.54L21.8489 131.729V130.966L23.4018 130.067V125.563L23.3382 125.599L21.8398 127.597V126.689L23.4018 124.6L24.1646 124.155V129.631L25.6448 128.777Z" fill="white"/>
+<path opacity="0.6" d="M27.6705 124.809L28.2698 124.464C28.851 124.128 29.2596 123.465 29.2596 122.848C29.2596 122.239 28.8692 122.067 28.2789 122.412C27.6886 122.757 27.3072 123.366 27.2527 124.038L26.5263 124.455C26.5807 123.32 27.2618 122.239 28.297 121.64C29.305 121.059 30.0043 121.322 30.0043 122.285C30.0043 123.03 29.6592 123.774 29.0689 124.265V124.337C29.7954 124.028 30.2222 124.355 30.2222 125.2C30.2222 126.281 29.4322 127.488 28.3152 128.133C27.2164 128.769 26.4627 128.487 26.4082 127.407L27.1347 126.989C27.1892 127.597 27.6432 127.743 28.288 127.361C28.9872 126.953 29.4322 126.281 29.4322 125.618C29.4322 124.937 28.9781 124.764 28.2698 125.182L27.6432 125.545V124.809H27.6705Z" fill="white"/>
+<path opacity="0.6" d="M33.0452 118.898C34.0714 118.308 34.7706 118.616 34.7706 119.67C34.7706 120.324 34.4982 121.023 33.6173 122.594L32.4095 124.773V124.846L34.8523 123.438V124.228L31.3198 126.272V125.654L33.1269 122.349C33.8262 121.068 33.9987 120.641 33.9987 120.169C33.9987 119.525 33.6082 119.343 33.0089 119.679C32.4095 120.024 32.01 120.714 32.01 121.413V121.441L31.2744 121.867V121.84C31.2926 120.714 32.0191 119.497 33.0452 118.898Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 122.121C37.1045 121.658 37.4223 121.086 37.8219 120.859C38.2215 120.632 38.5393 120.823 38.5393 121.295C38.5393 121.758 38.2215 122.33 37.8219 122.557C37.4223 122.784 37.1045 122.585 37.1045 122.121Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 115.565C44.4509 117.654 43.7789 119.207 42.5712 119.906C41.3634 120.605 40.6914 119.833 40.6914 117.736C40.6914 115.638 41.3634 114.085 42.5712 113.386C43.7789 112.696 44.4509 113.468 44.4509 115.565ZM43.5519 114.721C43.3885 114.076 43.0525 113.885 42.5712 114.167C41.8447 114.585 41.4542 115.674 41.4542 117.3C41.4542 117.49 41.4542 117.663 41.4724 117.826L43.5519 114.721ZM41.5813 118.598C41.7539 119.234 42.0808 119.425 42.5712 119.143C43.2976 118.725 43.679 117.636 43.679 116.01C43.679 115.82 43.67 115.638 43.6609 115.474L41.5813 118.598Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 112.832C49.2009 114.92 48.5289 116.473 47.3212 117.172C46.1134 117.872 45.4414 117.1 45.4414 115.002C45.4414 112.904 46.1134 111.352 47.3212 110.652C48.5199 109.953 49.2009 110.734 49.2009 112.832ZM48.3019 111.978C48.1385 111.333 47.8025 111.143 47.3212 111.424C46.5947 111.842 46.2042 112.932 46.2042 114.557C46.2042 114.748 46.2042 114.92 46.2224 115.084L48.3019 111.978ZM46.3223 115.856C46.4948 116.491 46.8217 116.682 47.3121 116.401C48.0386 115.983 48.42 114.893 48.42 113.268C48.42 113.077 48.4109 112.895 48.4018 112.732L46.3223 115.856Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 151.318V152.08L21.8489 154.269V153.506L23.4018 152.607V148.103L23.3382 148.139L21.8398 150.137V149.229L23.4018 147.14L24.1646 146.695V152.171L25.6448 151.318Z" fill="white"/>
+<path opacity="0.6" d="M28.9047 148.92L26.4619 150.327V149.61L28.2418 144.343L29.0318 143.889L27.2883 149.038V149.101L28.9229 148.157V146.431L29.6221 146.023V147.748L30.4212 147.285V148.039L29.6312 148.493V149.773L28.9047 150.191V148.92Z" fill="white"/>
+<path opacity="0.6" d="M34.9617 143.58C34.9617 145.669 34.2897 147.222 33.0819 147.921C31.8741 148.62 31.2021 147.848 31.2021 145.751C31.2021 143.653 31.8741 142.1 33.0819 141.401C34.2897 140.711 34.9617 141.492 34.9617 143.58ZM34.0627 142.736C33.8992 142.091 33.5632 141.9 33.0819 142.182C32.3554 142.599 31.965 143.689 31.965 145.315C31.965 145.505 31.965 145.678 31.9831 145.841L34.0627 142.736ZM32.0921 146.613C32.2555 147.249 32.5915 147.44 33.0819 147.158C33.8084 146.74 34.1898 145.651 34.1898 144.025C34.1898 143.834 34.1898 143.653 34.1716 143.489L32.0921 146.613Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 144.661C37.1045 144.198 37.4223 143.626 37.8219 143.399C38.2215 143.172 38.5393 143.362 38.5393 143.835C38.5393 144.298 38.2215 144.87 37.8219 145.097C37.4223 145.324 37.1045 145.124 37.1045 144.661Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 138.104C44.4509 140.193 43.7789 141.746 42.5712 142.445C41.3634 143.144 40.6914 142.372 40.6914 140.275C40.6914 138.177 41.3634 136.624 42.5712 135.925C43.7789 135.235 44.4509 136.007 44.4509 138.104ZM43.5519 137.26C43.3885 136.615 43.0525 136.424 42.5712 136.706C41.8447 137.124 41.4542 138.213 41.4542 139.839C41.4542 140.029 41.4542 140.202 41.4724 140.365L43.5519 137.26ZM41.5813 141.137C41.7539 141.773 42.0808 141.964 42.5712 141.682C43.2976 141.265 43.679 140.175 43.679 138.549C43.679 138.359 43.67 138.177 43.6609 138.014L41.5813 141.137Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 135.362C49.2009 137.451 48.5289 139.003 47.3212 139.703C46.1134 140.402 45.4414 139.63 45.4414 137.532C45.4414 135.435 46.1134 133.882 47.3212 133.182C48.5199 132.492 49.2009 133.273 49.2009 135.362ZM48.3019 134.517C48.1385 133.873 47.8025 133.682 47.3212 133.963C46.5947 134.381 46.2042 135.471 46.2042 137.096C46.2042 137.287 46.2042 137.46 46.2224 137.623L48.3019 134.517ZM46.3223 138.395C46.4948 139.031 46.8217 139.221 47.3121 138.94C48.0386 138.522 48.42 137.432 48.42 135.807C48.42 135.616 48.4109 135.435 48.4018 135.271L46.3223 138.395Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M30.1213 159.98V160.743L26.3255 162.931V162.169L27.8783 161.27V156.765L27.8148 156.802L26.3164 158.8V157.891L27.8783 155.803L28.6411 155.358V160.834L30.1213 159.98Z" fill="white"/>
+<path opacity="0.6" d="M32.7815 152.843C33.8077 152.252 34.5069 152.561 34.5069 153.615C34.5069 154.268 34.2345 154.968 33.3536 156.539L32.1459 158.718V158.791L34.5887 157.383V158.173L31.0561 160.217V159.599L32.8633 156.294C33.5625 155.013 33.735 154.586 33.735 154.114C33.735 153.469 33.3446 153.288 32.7452 153.624C32.1459 153.969 31.7463 154.659 31.7463 155.358V155.385L31.0107 155.812V155.785C31.0198 154.65 31.7463 153.433 32.7815 152.843Z" fill="white"/>
+<path opacity="0.6" d="M36.832 156.066C36.832 155.603 37.1499 155.031 37.5494 154.804C37.949 154.577 38.2668 154.768 38.2668 155.24C38.2668 155.703 37.9399 156.275 37.5494 156.502C37.1589 156.729 36.832 156.529 36.832 156.066Z" fill="white"/>
+<path opacity="0.6" d="M44.1882 149.51C44.1882 151.599 43.5162 153.152 42.3085 153.851C41.1007 154.55 40.4287 153.778 40.4287 151.68C40.4287 149.583 41.1007 148.03 42.3085 147.331C43.5162 146.64 44.1882 147.412 44.1882 149.51ZM43.2892 148.656C43.1258 148.012 42.7898 147.821 42.3085 148.103C41.582 148.52 41.1915 149.61 41.1915 151.235C41.1915 151.426 41.1915 151.599 41.2097 151.762L43.2892 148.656ZM41.3186 152.534C41.4912 153.17 41.8181 153.36 42.3085 153.079C43.035 152.661 43.4164 151.571 43.4164 149.946C43.4164 149.755 43.4073 149.574 43.3982 149.41L41.3186 152.534Z" fill="white"/>
+<path opacity="0.6" d="M48.9275 146.767C48.9275 148.856 48.2555 150.409 47.0477 151.108C45.84 151.807 45.168 151.035 45.168 148.938C45.168 146.84 45.84 145.287 47.0477 144.588C48.2555 143.898 48.9275 144.67 48.9275 146.767ZM48.0285 145.923C47.865 145.278 47.529 145.087 47.0477 145.369C46.3213 145.787 45.9308 146.876 45.9308 148.502C45.9308 148.693 45.9308 148.865 45.9489 149.029L48.0285 145.923ZM46.0579 149.8C46.2304 150.436 46.5574 150.627 47.0477 150.345C47.7742 149.928 48.1556 148.838 48.1556 147.212C48.1556 147.022 48.1465 146.84 48.1374 146.677L46.0579 149.8Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 174.746V175.509L21.8489 177.697V176.934L23.4018 176.035V171.531L23.3382 171.567L21.8398 173.565V172.657L23.4018 170.569L24.1646 170.124V175.599L25.6448 174.746Z" fill="white"/>
+<path opacity="0.6" d="M27.6705 170.777L28.2698 170.432C28.851 170.096 29.2596 169.433 29.2596 168.816C29.2596 168.207 28.8692 168.035 28.2789 168.38C27.6886 168.725 27.3072 169.333 27.2527 170.005L26.5263 170.423C26.5807 169.288 27.2618 168.207 28.297 167.608C29.305 167.027 30.0043 167.29 30.0043 168.253C30.0043 168.997 29.6592 169.742 29.0689 170.232V170.305C29.7954 169.996 30.2222 170.323 30.2222 171.168C30.2222 172.248 29.4322 173.456 28.3152 174.101C27.2164 174.736 26.4627 174.455 26.4082 173.374L27.1347 172.957C27.1892 173.565 27.6432 173.71 28.288 173.329C28.9872 172.92 29.4322 172.248 29.4322 171.585C29.4322 170.904 28.9781 170.732 28.2698 171.15L27.6432 171.513V170.777H27.6705Z" fill="white"/>
+<path opacity="0.6" d="M33.0452 164.875C34.0714 164.285 34.7706 164.593 34.7706 165.647C34.7706 166.301 34.4982 167 33.6173 168.571L32.4095 170.75V170.823L34.8523 169.415V170.206L31.3198 172.249V171.631L33.1269 168.326C33.8262 167.045 33.9987 166.619 33.9987 166.146C33.9987 165.502 33.6082 165.32 33.0089 165.656C32.4095 166.001 32.01 166.691 32.01 167.39V167.418L31.2744 167.844V167.817C31.2926 166.682 32.0191 165.465 33.0452 164.875Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 168.098C37.1045 167.635 37.4223 167.063 37.8219 166.836C38.2215 166.609 38.5393 166.8 38.5393 167.272C38.5393 167.735 38.2215 168.307 37.8219 168.534C37.4223 168.752 37.1045 168.562 37.1045 168.098Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 161.542C44.4509 163.63 43.7789 165.183 42.5712 165.882C41.3634 166.582 40.6914 165.81 40.6914 163.712C40.6914 161.614 41.3634 160.061 42.5712 159.362C43.7789 158.663 44.4509 159.444 44.4509 161.542ZM43.5519 160.688C43.3885 160.043 43.0525 159.853 42.5712 160.134C41.8447 160.552 41.4542 161.642 41.4542 163.267C41.4542 163.458 41.4542 163.63 41.4724 163.794L43.5519 160.688ZM41.5813 164.566C41.7539 165.201 42.0808 165.392 42.5712 165.111C43.2976 164.693 43.679 163.603 43.679 161.978C43.679 161.787 43.67 161.605 43.6609 161.442L41.5813 164.566Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 158.8C49.2009 160.888 48.5289 162.441 47.3212 163.14C46.1134 163.84 45.4414 163.068 45.4414 160.97C45.4414 158.872 46.1134 157.319 47.3212 156.62C48.5199 155.93 49.2009 156.702 49.2009 158.8ZM48.3019 157.955C48.1385 157.31 47.8025 157.12 47.3212 157.401C46.5947 157.819 46.2042 158.909 46.2042 160.534C46.2042 160.725 46.2042 160.897 46.2224 161.061L48.3019 157.955ZM46.3223 161.824C46.4948 162.459 46.8217 162.65 47.3121 162.368C48.0386 161.951 48.42 160.861 48.42 159.236C48.42 159.045 48.4109 158.863 48.4018 158.7L46.3223 161.824Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 186.506V187.268L21.8489 189.457V188.694L23.4018 187.795V183.291L23.3382 183.327L21.8398 185.325V184.417L23.4018 182.328L24.1646 181.883V187.359L25.6448 186.506Z" fill="white"/>
+<path opacity="0.6" d="M28.9047 184.109L26.4619 185.516V184.799L28.2418 179.532L29.0318 179.078L27.2883 184.227V184.29L28.9229 183.346V181.62L29.6221 181.212V182.937L30.4212 182.474V183.228L29.6312 183.682V184.962L28.9047 185.38V184.109Z" fill="white"/>
+<path opacity="0.6" d="M34.9617 178.769C34.9617 180.857 34.2897 182.41 33.0819 183.11C31.8741 183.809 31.2021 183.037 31.2021 180.939C31.2021 178.842 31.8741 177.289 33.0819 176.589C34.2897 175.899 34.9617 176.671 34.9617 178.769ZM34.0627 177.924C33.8992 177.28 33.5632 177.089 33.0819 177.37C32.3554 177.788 31.965 178.878 31.965 180.503C31.965 180.694 31.965 180.867 31.9831 181.03L34.0627 177.924ZM32.0921 181.802C32.2555 182.438 32.5915 182.628 33.0819 182.347C33.8084 181.929 34.1898 180.839 34.1898 179.214C34.1898 179.023 34.1898 178.841 34.1716 178.678L32.0921 181.802Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 179.849C37.1045 179.386 37.4223 178.814 37.8219 178.587C38.2215 178.36 38.5393 178.551 38.5393 179.023C38.5393 179.486 38.2215 180.058 37.8219 180.285C37.4223 180.512 37.1045 180.313 37.1045 179.849Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 173.293C44.4509 175.382 43.7789 176.935 42.5712 177.634C41.3634 178.333 40.6914 177.561 40.6914 175.464C40.6914 173.366 41.3634 171.813 42.5712 171.114C43.7789 170.424 44.4509 171.196 44.4509 173.293ZM43.5519 172.449C43.3885 171.804 43.0525 171.613 42.5712 171.895C41.8447 172.313 41.4542 173.402 41.4542 175.028C41.4542 175.218 41.4542 175.391 41.4724 175.554L43.5519 172.449ZM41.5813 176.326C41.7539 176.962 42.0808 177.153 42.5712 176.871C43.2976 176.453 43.679 175.364 43.679 173.738C43.679 173.548 43.67 173.366 43.6609 173.202L41.5813 176.326Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 170.551C49.2009 172.639 48.5289 174.192 47.3212 174.891C46.1134 175.591 45.4414 174.819 45.4414 172.721C45.4414 170.623 46.1134 169.07 47.3212 168.371C48.5199 167.681 49.2009 168.453 49.2009 170.551ZM48.3019 169.706C48.1385 169.061 47.8025 168.871 47.3212 169.152C46.5947 169.57 46.2042 170.66 46.2042 172.285C46.2042 172.476 46.2042 172.648 46.2224 172.812L48.3019 169.706ZM46.3223 173.584C46.4948 174.219 46.8217 174.41 47.3121 174.129C48.0386 173.711 48.42 172.621 48.42 170.996C48.42 170.805 48.4109 170.623 48.4018 170.46L46.3223 173.584Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M30.1213 195.169V195.932L26.3255 198.12V197.358L27.8783 196.459V191.954L27.8148 191.991L26.3164 193.989V193.08L27.8783 190.992L28.6411 190.547V196.023L30.1213 195.169Z" fill="white"/>
+<path opacity="0.6" d="M32.7815 188.032C33.8077 187.441 34.5069 187.75 34.5069 188.804C34.5069 189.457 34.2345 190.157 33.3536 191.728L32.1459 193.907V193.98L34.5887 192.572V193.362L31.0561 195.405V194.788L32.8633 191.482C33.5625 190.202 33.735 189.775 33.735 189.303C33.735 188.658 33.3446 188.477 32.7452 188.813C32.1459 189.158 31.7463 189.848 31.7463 190.547V190.574L31.0107 191.001V190.974C31.0198 189.839 31.7463 188.622 32.7815 188.032Z" fill="white"/>
+<path opacity="0.6" d="M36.832 191.255C36.832 190.792 37.1499 190.22 37.5494 189.993C37.949 189.766 38.2668 189.957 38.2668 190.429C38.2668 190.892 37.9399 191.464 37.5494 191.691C37.1589 191.918 36.832 191.718 36.832 191.255Z" fill="white"/>
+<path opacity="0.6" d="M44.1882 184.699C44.1882 186.788 43.5162 188.341 42.3085 189.04C41.1007 189.739 40.4287 188.967 40.4287 186.869C40.4287 184.772 41.1007 183.219 42.3085 182.52C43.5162 181.829 44.1882 182.601 44.1882 184.699ZM43.2892 183.845C43.1258 183.201 42.7898 183.01 42.3085 183.291C41.582 183.709 41.1915 184.799 41.1915 186.424C41.1915 186.615 41.1915 186.788 41.2097 186.951L43.2892 183.845ZM41.3186 187.723C41.4912 188.359 41.8181 188.549 42.3085 188.268C43.035 187.85 43.4164 186.76 43.4164 185.135C43.4164 184.944 43.4073 184.763 43.3982 184.599L41.3186 187.723Z" fill="white"/>
+<path opacity="0.6" d="M48.9275 181.956C48.9275 184.045 48.2555 185.598 47.0477 186.297C45.84 186.996 45.168 186.224 45.168 184.127C45.168 182.029 45.84 180.476 47.0477 179.777C48.2555 179.087 48.9275 179.859 48.9275 181.956ZM48.0285 181.112C47.865 180.467 47.529 180.276 47.0477 180.558C46.3213 180.976 45.9308 182.065 45.9308 183.691C45.9308 183.882 45.9308 184.054 45.9489 184.218L48.0285 181.112ZM46.0579 184.989C46.2304 185.625 46.5574 185.816 47.0477 185.534C47.7742 185.117 48.1556 184.027 48.1556 182.401C48.1556 182.211 48.1465 182.029 48.1374 181.866L46.0579 184.989Z" fill="white"/>
+</g>
+<g opacity="0.6">
+<path opacity="0.6" d="M25.6448 209.935V210.698L21.8489 212.887V212.124L23.4018 211.225V206.721L23.3382 206.757L21.8398 208.755V207.847L23.4018 205.758L24.1646 205.313V210.789L25.6448 209.935Z" fill="white"/>
+<path opacity="0.6" d="M27.6705 205.967L28.2698 205.622C28.851 205.286 29.2596 204.623 29.2596 204.005C29.2596 203.397 28.8692 203.224 28.2789 203.569C27.6886 203.914 27.3072 204.523 27.2527 205.195L26.5263 205.612C26.5807 204.477 27.2618 203.397 28.297 202.797C29.305 202.216 30.0043 202.48 30.0043 203.442C30.0043 204.187 29.6592 204.931 29.0689 205.422V205.494C29.7954 205.186 30.2222 205.513 30.2222 206.357C30.2222 207.438 29.4322 208.646 28.3152 209.29C27.2164 209.926 26.4627 209.644 26.4082 208.564L27.1347 208.146C27.1892 208.755 27.6432 208.9 28.288 208.518C28.9872 208.11 29.4322 207.438 29.4322 206.775C29.4322 206.094 28.9781 205.921 28.2698 206.339L27.6432 206.702V205.967H27.6705Z" fill="white"/>
+<path opacity="0.6" d="M33.0452 200.064C34.0714 199.474 34.7706 199.783 34.7706 200.836C34.7706 201.49 34.4982 202.189 33.6173 203.76L32.4095 205.94V206.012L34.8523 204.605V205.395L31.3198 207.438V206.821L33.1269 203.515C33.8262 202.235 33.9987 201.808 33.9987 201.336C33.9987 200.691 33.6082 200.509 33.0089 200.845C32.4095 201.19 32.01 201.881 32.01 202.58V202.607L31.2744 203.034V203.007C31.2926 201.872 32.0191 200.655 33.0452 200.064Z" fill="white"/>
+<path opacity="0.6" d="M37.1045 203.279C37.1045 202.815 37.4223 202.243 37.8219 202.016C38.2215 201.789 38.5393 201.98 38.5393 202.452C38.5393 202.915 38.2215 203.487 37.8219 203.715C37.4223 203.942 37.1045 203.742 37.1045 203.279Z" fill="white"/>
+<path opacity="0.6" d="M44.4509 196.722C44.4509 198.811 43.7789 200.364 42.5712 201.063C41.3634 201.762 40.6914 200.99 40.6914 198.893C40.6914 196.795 41.3634 195.242 42.5712 194.543C43.7789 193.853 44.4509 194.634 44.4509 196.722ZM43.5519 195.878C43.3885 195.233 43.0525 195.042 42.5712 195.324C41.8447 195.742 41.4542 196.831 41.4542 198.457C41.4542 198.647 41.4542 198.82 41.4724 198.983L43.5519 195.878ZM41.5813 199.755C41.7539 200.391 42.0808 200.582 42.5712 200.3C43.2976 199.882 43.679 198.793 43.679 197.167C43.679 196.977 43.67 196.795 43.6609 196.631L41.5813 199.755Z" fill="white"/>
+<path opacity="0.6" d="M49.2009 193.989C49.2009 196.078 48.5289 197.631 47.3212 198.33C46.1134 199.029 45.4414 198.257 45.4414 196.159C45.4414 194.062 46.1134 192.509 47.3212 191.81C48.5199 191.119 49.2009 191.891 49.2009 193.989ZM48.3019 193.135C48.1385 192.491 47.8025 192.3 47.3212 192.582C46.5947 192.999 46.2042 194.089 46.2042 195.714C46.2042 195.905 46.2042 196.078 46.2224 196.241L48.3019 193.135ZM46.3223 197.013C46.4948 197.649 46.8217 197.839 47.3121 197.558C48.0386 197.14 48.42 196.05 48.42 194.425C48.42 194.234 48.4109 194.053 48.4018 193.889L46.3223 197.013Z" fill="white"/>
+</g>
+</g>
+<path d="M98.4106 64.6748L209.362 0.617544C211.868 -0.826333 213.903 0.345114 213.903 3.24195V162.804C213.903 165.701 211.868 169.215 209.362 170.668L98.4106 234.725C95.9043 236.169 93.8701 234.998 93.8701 232.101V72.539C93.8701 69.6421 95.9043 66.1278 98.4106 64.6748Z" fill="#363636"/>
+<path d="M104.604 199.291L203.596 142.145C204.713 141.5 205.612 142.027 205.612 143.307V160.443C205.612 161.732 204.713 163.294 203.596 163.939L104.604 221.086C103.487 221.73 102.588 221.204 102.588 219.923V202.788C102.588 201.498 103.487 199.936 104.604 199.291Z" fill="#424242"/>
+<path d="M100.444 66.4912L211.387 2.43395C213.893 0.990073 215.927 2.16152 215.927 5.05836V164.62C215.927 167.517 213.893 171.032 211.387 172.485L100.435 236.542C97.9287 237.986 95.8945 236.814 95.8945 233.917V74.3554C95.9036 71.4585 97.9378 67.9442 100.444 66.4912Z" fill="#424242"/>
+<path d="M100.444 66.4912L211.386 2.43395C213.893 0.990073 215.927 2.16152 215.927 5.05836V45.4506L95.9033 114.748V74.3554C95.9033 71.4585 97.9375 67.9442 100.444 66.4912Z" fill="#424242"/>
+<path d="M193.679 64.6748L304.631 0.617544C307.137 -0.826333 309.171 0.345114 309.171 3.24195V162.804C309.171 165.701 307.137 169.215 304.631 170.668L193.679 234.725C191.173 236.169 189.139 234.998 189.139 232.101V72.539C189.139 69.6421 191.173 66.1278 193.679 64.6748Z" fill="#424242"/>
+<path d="M193.679 64.6748L304.63 0.617544C307.137 -0.826333 309.171 0.345114 309.171 3.24195V43.6342L189.147 112.931V72.539C189.138 69.6421 191.173 66.1278 193.679 64.6748Z" fill="#424242"/>
+<path d="M203.968 76.8164L202.688 77.552C202.615 77.7064 202.134 79.577 200.554 80.4851V81.8745C201.625 81.257 202.361 80.3943 202.515 79.9675L202.588 79.9221V88.6126L203.959 87.8226V76.8164H203.968ZM213.194 78.9414L211.85 79.7133V72.2578L210.343 73.1295L206.202 83.3366V84.4354L210.543 81.929V84.0176L211.85 83.2639V81.1753L213.194 80.4034V78.9414ZM207.864 82.0198L210.343 75.763L210.543 75.1001V80.467L207.864 82.0198ZM220.85 71.84C220.85 68.6526 219.642 67.6174 217.617 68.7797C215.574 69.9603 214.357 72.4031 214.357 75.5905V76.8891C214.357 80.1401 215.592 81.2661 217.635 80.0856C219.66 78.9141 220.859 76.3896 220.859 73.1386V71.84H220.85ZM219.388 74.2465C219.388 76.2352 218.779 77.9606 217.626 78.6326C216.445 79.3137 215.81 78.3057 215.81 76.317V74.4826C215.81 72.5393 216.436 70.9138 217.617 70.2327C218.779 69.5607 219.397 70.4597 219.397 72.4121V74.2465H219.388ZM222.984 76.9526C223.501 76.653 223.928 75.9265 223.928 75.3181C223.928 74.7278 223.501 74.4917 222.984 74.7914C222.475 75.082 222.039 75.7993 222.039 76.4078C222.039 77.0162 222.457 77.2614 222.984 76.9526ZM231.447 65.7195C231.447 62.532 230.239 61.4968 228.214 62.6592C226.171 63.8397 224.954 66.2825 224.954 69.4699V70.7685C224.954 74.0195 226.189 75.1455 228.233 73.965C230.258 72.7935 231.456 70.269 231.456 67.018V65.7195H231.447ZM229.994 68.1259C229.994 70.1146 229.386 71.84 228.233 72.512C227.052 73.1931 226.416 72.1851 226.416 70.1964V68.362C226.416 66.4187 227.043 64.7932 228.223 64.1121C229.386 63.4401 230.003 64.3391 230.003 66.2916V68.1259H229.994ZM239.33 61.1699C239.33 57.9825 238.122 56.9472 236.097 58.1096C234.053 59.2901 232.837 61.7329 232.837 64.9203V66.2189C232.837 69.4699 234.072 70.5959 236.115 69.4154C238.14 68.244 239.339 65.7195 239.339 62.4685V61.1699H239.33ZM237.867 63.5763C237.867 65.5651 237.259 67.2905 236.106 67.9625C234.925 68.6435 234.29 67.6355 234.29 65.6468V63.8124C234.29 61.8691 234.916 60.2436 236.097 59.5625C237.259 58.8905 237.877 59.7896 237.877 61.742V63.5763H237.867ZM251.226 59.0812L246.231 61.969L251.189 50.6813V49.5553L244.406 53.4692V54.9312L249.4 52.0526L244.442 63.3402V64.4663L251.226 60.5524V59.0812ZM258.254 56.4841L259.925 55.5215L257.9 52.1434C258.935 51.0082 259.571 49.637 259.571 48.1205C259.571 46.1862 258.563 45.3054 256.302 46.6131L252.96 48.5382V59.5535L254.44 58.6998V54.4863L256.429 53.3421L258.254 56.4841ZM254.431 49.1466L256.293 48.0751C257.691 47.2669 258.109 47.9752 258.109 48.9832C258.109 50.1274 257.591 51.1808 256.202 51.9799L254.431 53.0061V49.1466ZM262.35 43.1078L260.643 44.0885L263.621 47.8753L260.624 55.1129L262.341 54.123L264.575 48.62L264.647 48.5745L266.881 51.4986L268.598 50.5088L265.646 46.7039L268.579 39.5117L266.872 40.4925L264.647 46.041L264.575 46.0864L262.35 43.1078Z" fill="#424242"/>
+<path d="M199.872 199.291L298.864 142.145C299.981 141.5 300.88 142.027 300.88 143.307V160.443C300.88 161.732 299.981 163.294 298.864 163.939L199.872 221.086C198.755 221.73 197.856 221.204 197.856 219.923V202.788C197.856 201.498 198.755 199.936 199.872 199.291Z" fill="#424242"/>
+<path opacity="0.2" d="M199.736 121.159L298.582 64.0936C299.136 63.7758 299.59 64.0301 299.59 64.6748V78.6505C299.59 79.2952 299.136 80.0762 298.582 80.394L199.736 137.459C199.182 137.777 198.728 137.522 198.728 136.878V122.902C198.728 122.266 199.173 121.485 199.736 121.159Z" fill="#424242"/>
+<path opacity="0.2" d="M198.864 183.272L296.721 126.771" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path opacity="0.2" d="M198.864 167.835L296.721 111.333" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path opacity="0.2" d="M198.864 153.305L296.721 96.8032" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path d="M115.601 82.0923L112.804 83.7087L112.123 86.7781L110.897 87.4864L113.549 76.2351L114.902 75.4541L117.554 83.6452L116.264 84.3898L115.601 82.0923ZM115.32 81.1206L114.23 77.4065L114.194 77.4338L113.095 82.4101L115.32 81.1206Z" fill="white"/>
+<path d="M121.64 73.8013C123.03 73.0022 123.938 73.2383 124.047 74.4551L122.93 75.0999C122.821 74.5641 122.33 74.4733 121.631 74.8819C120.887 75.3087 120.396 75.9989 120.396 76.6073C120.396 77.134 120.705 77.243 121.45 77.0069L122.376 76.7072C123.629 76.3076 124.192 76.5982 124.192 77.6789C124.192 79.0773 123.193 80.5394 121.64 81.4384C120.142 82.3011 119.17 82.0922 119.07 80.8572L120.251 80.1761C120.378 80.7301 120.905 80.7846 121.677 80.3396C122.476 79.8765 122.993 79.1682 122.993 78.5325C122.993 77.9967 122.712 77.8786 121.94 78.1238L120.986 78.4235C119.824 78.7867 119.252 78.4508 119.252 77.3792C119.225 76.0534 120.178 74.6458 121.64 73.8013Z" fill="white"/>
+<path d="M129.023 69.5332C130.413 68.7341 131.321 68.9702 131.43 70.187L130.304 70.8318C130.195 70.296 129.704 70.2052 129.005 70.6139C128.261 71.0407 127.77 71.7308 127.77 72.3392C127.77 72.8659 128.079 72.9749 128.824 72.7388L129.75 72.4391C131.003 72.0396 131.566 72.3302 131.566 73.4108C131.566 74.8093 130.567 76.2713 129.014 77.1703C127.516 78.033 126.544 77.8242 126.444 76.5891L127.625 75.9081C127.752 76.462 128.279 76.5165 129.051 76.0715C129.85 75.6084 130.367 74.9001 130.367 74.2644C130.367 73.7286 130.086 73.6106 129.314 73.8558L128.36 74.1554C127.198 74.5187 126.626 74.1827 126.626 73.1111C126.617 71.7853 127.561 70.3777 129.023 69.5332Z" fill="white"/>
+<path d="M139.13 69.2515C138.958 70.5864 137.914 72.0394 136.542 72.8294C134.753 73.8646 133.736 73.2381 133.736 71.1494V70.0325C133.736 68.0982 134.826 66.2003 136.479 65.2468C138.141 64.2842 139.149 64.9744 139.149 67.063V67.8621L134.881 70.3231V70.65C134.881 71.8941 135.525 72.3118 136.533 71.7306C137.287 71.2947 137.85 70.5955 138.013 69.9053L139.13 69.2515ZM134.881 69.3605L137.995 67.5624C137.995 66.2548 137.423 65.8007 136.461 66.3547C135.48 66.9177 134.881 68.0437 134.881 69.3605Z" fill="white"/>
+<path d="M143.78 59.1538V61.2061L146.295 59.7532V60.861L143.798 62.3049V66.2733C143.798 66.9998 144.234 67.1451 145.042 66.6819C145.342 66.5094 146.114 66.0463 146.259 65.9464V67.0543C146.132 67.1542 145.206 67.7172 144.96 67.8534C143.335 68.7887 142.617 68.5345 142.617 66.9544V62.986L140.938 63.9577V62.8407L142.617 61.869V59.8167L143.78 59.1538Z" fill="white"/>
+<path d="M157.174 59.6169L157.065 59.6805V60.8429L155.885 61.5239V51.3078L157.083 50.6177V54.6496L157.202 54.5861C157.456 53.6144 158.128 52.7699 159.036 52.2341C160.498 51.3896 161.433 52.0525 161.433 53.9776V55.3125C161.433 57.2286 160.498 58.9813 159.036 59.8258C158.128 60.3434 157.474 60.2708 157.174 59.6169ZM160.253 55.8665V54.7677C160.253 53.5054 159.635 53.0605 158.654 53.6326C157.683 54.1956 157.056 55.3489 157.056 56.6202V57.719C157.056 58.9813 157.683 59.4171 158.654 58.8541C159.635 58.2729 160.253 57.1197 160.253 55.8665Z" fill="white"/>
+<path d="M168.607 54.1683L167.472 54.8221V53.5508L167.391 53.5962C167.055 54.695 166.337 55.6213 165.393 56.1661C164.013 56.9652 163.259 56.4385 163.259 54.6768V49.9093L164.43 49.2282V53.6598C164.43 54.9129 164.866 55.2489 165.811 54.7132C166.782 54.1501 167.436 52.9878 167.436 51.7982V47.4938L168.598 46.8218V54.1683H168.607Z" fill="white"/>
+<path d="M171.032 55.3849V54.2498C171.095 54.2226 171.286 54.1227 171.386 54.0682C171.994 53.714 172.33 53.2237 172.566 52.3156L172.666 51.8978L170.351 45.8408L171.631 45.0962L173.302 50.1361L173.384 50.0907L175.045 43.1256L176.29 42.4082L173.956 51.3257C173.402 53.4688 172.802 54.3951 171.513 55.1397C171.331 55.2306 171.104 55.3395 171.032 55.3849Z" fill="white"/>
+<path d="M183.446 43.6617C183.273 44.9966 182.229 46.4495 180.858 47.2396C179.069 48.2748 178.052 47.6482 178.052 45.5596V44.4426C178.052 42.5084 179.141 40.6105 180.794 39.657C182.456 38.6944 183.464 39.3845 183.464 41.4731V42.2723L179.196 44.7332V45.0601C179.196 46.3042 179.841 46.722 180.849 46.1408C181.602 45.7049 182.165 45.0057 182.329 44.3155L183.446 43.6617ZM179.196 43.7706L182.311 41.9726C182.311 40.6649 181.739 40.2109 180.776 40.7648C179.795 41.3369 179.196 42.463 179.196 43.7706Z" fill="white"/>
+<path d="M188.04 37.4773C188.294 35.9517 189.03 34.8438 190.256 34.1355C190.619 33.9266 190.964 33.7813 191.173 33.7632V35.2434C190.891 35.2888 190.474 35.4432 190.119 35.6429C188.685 36.4693 187.886 37.9677 187.886 39.7657V41.9996L189.82 40.8827V41.9179L185.488 44.4152V43.38L186.75 42.6535V37.3865L185.37 38.1856V37.1504L187.886 35.6974V37.5681L188.04 37.4773Z" fill="white"/>
+<path d="M161.914 168.47L164.348 164.248C165.419 162.386 165.565 160.352 164.693 159.426L162.323 156.892C163.24 154.531 163.948 152.161 164.42 149.836L168.48 146.667C169.987 145.514 171.086 143.371 171.095 141.609V137.586C171.086 135.824 169.987 134.962 168.48 135.543L164.42 137.059C163.948 135.288 163.24 133.736 162.323 132.428L164.693 127.206C165.565 125.272 165.419 123.401 164.348 122.784L161.914 121.376C160.843 120.759 159.153 121.567 157.909 123.283L154.531 127.969C152.942 127.824 151.244 127.996 149.473 128.469L148.756 124.191C148.501 122.602 147.203 122.076 145.686 122.947L142.199 124.954C140.674 125.844 139.375 127.86 139.13 129.749L138.412 134.843C136.642 136.415 134.944 138.213 133.354 140.183L130.022 139.375C128.778 139.084 127.088 140.229 126.017 142.09L123.583 146.313C122.521 148.174 122.385 150.199 123.265 151.126L125.636 153.659C124.718 156.02 124.01 158.39 123.538 160.715L119.479 163.884C117.971 165.038 116.872 167.181 116.863 168.943V172.965C116.872 174.727 117.971 175.59 119.479 175.009L123.538 173.492C124.01 175.263 124.718 176.816 125.636 178.123L123.265 183.345C122.394 185.279 122.539 187.15 123.61 187.767L126.044 189.175C127.116 189.793 128.805 188.984 130.049 187.268L133.427 182.582C135.016 182.728 136.714 182.555 138.485 182.083L139.203 186.36C139.457 187.949 140.755 188.476 142.272 187.604L145.759 185.597C147.285 184.707 148.583 182.691 148.828 180.802L149.546 175.708C151.317 174.137 153.015 172.339 154.604 170.368L157.909 171.158C159.144 171.458 160.833 170.332 161.914 168.47ZM198.946 76.0623C198.547 74.6002 197.166 74.2824 195.659 75.3085L191.963 77.8149C190.674 76.3165 189.012 75.3539 187.068 74.9907L187.386 70.541C187.522 68.7157 186.551 67.6714 185.08 68.0619L181.756 68.9791C180.285 69.3877 178.741 71.1222 178.115 73.0928L176.544 77.8149C174.219 79.3133 171.949 81.3292 169.869 83.7357L166.827 83.0274C165.583 82.7368 163.894 83.881 162.822 85.7426L160.388 89.9652C159.317 91.8268 159.172 93.861 160.043 94.7872L162.205 97.0484C161.16 100.054 160.552 103.024 160.416 105.793L157.019 109.607C155.63 111.133 154.894 113.331 155.276 114.82L156.148 118.162C156.538 119.633 157.928 119.951 159.435 118.925L163.131 116.418C164.42 117.917 166.082 118.879 168.026 119.242L167.708 123.692C167.599 125.499 168.58 126.516 170.042 126.108L173.365 125.19C174.836 124.782 176.38 123.047 177.007 121.077L178.578 116.282C180.911 114.793 183.2 112.786 185.289 110.388L188.331 111.124C189.575 111.415 191.264 110.27 192.335 108.409L194.769 104.186C195.841 102.324 195.986 100.29 195.114 99.3641L192.98 97.0847C194.024 94.0789 194.633 91.1094 194.769 88.3397L198.138 84.5802C199.528 83.0546 200.263 80.857 199.882 79.3677L198.946 76.0623ZM177.642 94.2151L171.894 100.554L177.642 101.153L183.391 93.9064L177.642 94.2151ZM171.894 100.554L177.642 101.153V86.2148L171.894 100.554ZM177.642 86.2148V101.162L183.391 93.9155L177.642 86.2148ZM171.894 101.816L177.642 107.855V102.424L171.894 101.816ZM177.642 102.415V107.846L183.4 95.1687L177.642 102.415Z" stroke="white" stroke-width="1.18552" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M137.731 171.949C139.275 172.094 141.037 171.731 142.935 170.777C145.559 169.461 148.038 167.218 150.1 164.511C151.126 163.167 152.043 161.696 152.824 160.171C152.179 159.508 151.489 158.827 150.763 158.155C150.563 157.973 150.363 157.791 150.163 157.61C149.382 159.49 148.256 161.279 146.93 162.759L144.896 161.633L137.731 171.949Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
+<path d="M133.381 155.757C132.501 158.028 131.947 160.361 131.829 162.595C131.656 165.719 132.355 168.189 133.681 169.806C134.335 170.605 135.143 171.195 136.069 171.567C136.968 170.296 137.904 168.961 138.848 167.572C139.102 167.199 139.357 166.818 139.62 166.437C138.385 166.246 137.404 165.519 136.787 164.348L138.794 160.825L133.381 155.757Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
+<path d="M149.681 141.3C148.138 141.155 146.376 141.518 144.469 142.472C141.845 143.789 139.365 146.032 137.304 148.747C136.287 150.091 135.37 151.544 134.589 153.069C135.234 153.732 135.924 154.413 136.65 155.085C136.85 155.267 137.05 155.449 137.25 155.63C138.031 153.76 139.157 151.971 140.482 150.49L142.399 151.544L149.681 141.3Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
+<path d="M154.05 157.419C154.913 155.176 155.458 152.87 155.576 150.654C155.748 147.53 155.049 145.069 153.732 143.453C153.078 142.644 152.27 142.054 151.335 141.691C150.436 142.962 149.5 144.297 148.556 145.677C148.302 146.05 148.048 146.431 147.784 146.813C149.019 147.003 150.009 147.739 150.627 148.91L150.636 148.938L148.71 152.361L154.05 157.419Z" stroke="white" stroke-width="1.42299" stroke-miterlimit="10"/>
+<path d="M195.713 66.4912L306.655 2.43395C309.161 0.990073 311.196 2.16152 311.196 5.05836V164.62C311.196 167.517 309.161 171.032 306.655 172.485L195.704 236.542C193.197 237.986 191.163 236.814 191.163 233.917V74.3554C191.172 71.4585 193.206 67.9442 195.713 66.4912Z" fill="#B0B0B0"/>
+<path d="M195.712 66.4912L306.655 2.43395C309.161 0.990073 311.195 2.16152 311.195 5.05836V45.4506L191.172 114.748V74.3554C191.172 71.4585 193.206 67.9442 195.712 66.4912Z" fill="#4F4F4F"/>
+<path opacity="0.3" d="M205.993 78.6323L204.712 79.3679C204.64 79.5223 204.158 81.393 202.578 82.3011V83.6905C203.65 83.0729 204.385 82.2102 204.54 81.7834L204.612 81.738V90.4285L205.983 89.6385V78.6323H205.993ZM215.219 80.7573L213.875 81.5292V74.0737L212.367 74.9455L208.227 85.1525V86.2513L212.567 83.7449V85.8336L213.875 85.0798V82.9912L215.219 82.2193V80.7573ZM209.888 83.8357L212.367 77.5789L212.567 76.916V82.2829L209.888 83.8357ZM222.874 73.656C222.874 70.4685 221.666 69.4333 219.641 70.5957C217.598 71.7762 216.381 74.219 216.381 77.4064V78.705C216.381 81.956 217.616 83.082 219.659 81.9015C221.685 80.73 222.883 78.2055 222.883 74.9545V73.656H222.874ZM221.421 76.0624C221.421 78.0512 220.813 79.7765 219.659 80.4485C218.479 81.1296 217.843 80.1216 217.843 78.1329V76.2985C217.843 74.3552 218.47 72.7297 219.65 72.0486C220.813 71.3766 221.43 72.2756 221.43 74.2281V76.0624H221.421ZM225.008 78.7686C225.526 78.4689 225.953 77.7424 225.953 77.134C225.953 76.5437 225.526 76.3076 225.008 76.6073C224.5 76.8979 224.064 77.6153 224.064 78.2237C224.073 78.8321 224.491 79.0773 225.008 78.7686ZM233.481 67.5354C233.481 64.3479 232.273 63.3127 230.248 64.4751C228.205 65.6556 226.988 68.0984 226.988 71.2858V72.5844C226.988 75.8354 228.223 76.9614 230.266 75.7809C232.291 74.6095 233.49 72.0849 233.49 68.834V67.5354H233.481ZM232.019 69.9418C232.019 71.9306 231.41 73.656 230.257 74.3279C229.076 75.009 228.441 74.001 228.441 72.0123V70.1779C228.441 68.2346 229.067 66.6091 230.248 65.928C231.41 65.256 232.028 66.1551 232.028 68.1075V69.9418H232.019ZM241.354 62.9858C241.354 59.7984 240.146 58.7631 238.121 59.9255C236.078 61.106 234.861 63.5488 234.861 66.7362V68.0348C234.861 71.2858 236.096 72.4119 238.139 71.2313C240.164 70.0599 241.363 67.5354 241.363 64.2844V62.9858H241.354ZM239.901 65.3923C239.901 67.381 239.293 69.1064 238.139 69.7784C236.959 70.4594 236.323 69.4515 236.323 67.4627V65.6284C236.323 63.685 236.95 62.0595 238.13 61.3785C239.293 60.7065 239.91 61.6055 239.91 63.5579V65.3923H239.901ZM253.25 60.8972L248.255 63.7849L253.214 52.4973V51.3712L246.43 55.2851V56.7472L251.425 53.8685L246.467 65.1562V66.2822L253.25 62.3683V60.8972ZM260.279 58.3L261.95 57.3374L259.925 53.9593C260.96 52.8242 261.595 51.4529 261.595 49.9364C261.595 48.0022 260.587 47.1213 258.326 48.429L254.985 50.3541V61.3694L256.465 60.5158V56.3022L258.453 55.158L260.279 58.3ZM256.456 50.9626L258.317 49.891C259.716 49.0828 260.133 49.7911 260.133 50.7991C260.133 51.9433 259.616 52.9967 258.226 53.7958L256.456 54.822V50.9626ZM264.383 44.9237L262.676 45.9045L265.655 49.6912L262.658 56.9288L264.374 55.9389L266.608 50.4359L266.681 50.3905L268.915 53.3145L270.631 52.3247L267.68 48.5198L270.613 41.3276L268.906 42.3084L266.681 47.8569L266.608 47.9023L264.383 44.9237Z" fill="white"/>
+<path d="M201.897 201.108L300.889 143.961C302.006 143.316 302.905 143.843 302.905 145.123V162.259C302.905 163.549 302.006 165.111 300.889 165.755L201.897 222.902C200.78 223.547 199.881 223.02 199.881 221.74V204.604C199.881 203.314 200.78 201.753 201.897 201.108Z" fill="#4F4F4F"/>
+<path opacity="0.2" d="M201.761 122.975L300.607 65.91C301.161 65.5922 301.615 65.8465 301.615 66.4912V80.4669C301.615 81.1116 301.161 81.8926 300.607 82.2104L201.761 139.275C201.207 139.593 200.753 139.339 200.753 138.694V124.719C200.753 124.083 201.207 123.302 201.761 122.975Z" fill="white"/>
+<path opacity="0.2" d="M200.889 185.089L298.745 128.587" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path opacity="0.2" d="M200.889 169.651L298.745 113.149" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+<path opacity="0.2" d="M200.889 155.122L298.745 98.6196" stroke="white" stroke-width="2.16763" stroke-linecap="round"/>
+</g>
+<defs>
+<clipPath id="clip0">
+<rect width="311.196" height="237.15" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/packages/website/public/images/instant/gnt_screenshot.png b/packages/website/public/images/instant/gnt_screenshot.png
new file mode 100644
index 000000000..595c92703
--- /dev/null
+++ b/packages/website/public/images/instant/gnt_screenshot.png
Binary files differ
diff --git a/packages/website/public/images/instant/gods_screenshot.png b/packages/website/public/images/instant/gods_screenshot.png
new file mode 100644
index 000000000..07dcd3b7c
--- /dev/null
+++ b/packages/website/public/images/instant/gods_screenshot.png
Binary files differ
diff --git a/packages/website/public/images/instant/kitty_screenshot.png b/packages/website/public/images/instant/kitty_screenshot.png
new file mode 100644
index 000000000..cf201f8d9
--- /dev/null
+++ b/packages/website/public/images/instant/kitty_screenshot.png
Binary files differ
diff --git a/packages/website/public/images/instant/nmr_screenshot.png b/packages/website/public/images/instant/nmr_screenshot.png
new file mode 100644
index 000000000..9b13e59d7
--- /dev/null
+++ b/packages/website/public/images/instant/nmr_screenshot.png
Binary files differ
diff --git a/packages/website/public/images/instant/rep_screenshot.png b/packages/website/public/images/instant/rep_screenshot.png
new file mode 100644
index 000000000..813787c16
--- /dev/null
+++ b/packages/website/public/images/instant/rep_screenshot.png
Binary files differ
diff --git a/packages/website/ts/components/ui/image.tsx b/packages/website/ts/components/ui/image.tsx
index c8d39352b..d698ddaa0 100644
--- a/packages/website/ts/components/ui/image.tsx
+++ b/packages/website/ts/components/ui/image.tsx
@@ -10,6 +10,7 @@ export interface ImageProps {
height?: string | number;
maxWidth?: string | number;
maxHeight?: string | number;
+ additionalStyle?: React.CSSProperties;
}
interface ImageState {
imageLoadFailed: boolean;
@@ -30,6 +31,7 @@ export class Image extends React.Component<ImageProps, ImageState> {
onError={this._onError.bind(this)}
src={src}
style={{
+ ...this.props.additionalStyle,
borderRadius: this.props.borderRadius,
maxWidth: this.props.maxWidth,
maxHeight: this.props.maxHeight,
diff --git a/packages/website/ts/components/ui/text.tsx b/packages/website/ts/components/ui/text.tsx
index 2fe2a8c79..046442ee5 100644
--- a/packages/website/ts/components/ui/text.tsx
+++ b/packages/website/ts/components/ui/text.tsx
@@ -3,7 +3,7 @@ import { darken } from 'polished';
import * as React from 'react';
import { styled } from 'ts/style/theme';
-export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i';
+export type TextTag = 'p' | 'div' | 'span' | 'label' | 'h1' | 'h2' | 'h3' | 'h4' | 'i' | 'span';
export interface TextProps {
className?: string;
diff --git a/packages/website/ts/containers/instant.ts b/packages/website/ts/containers/instant.ts
new file mode 100644
index 000000000..12ae7454e
--- /dev/null
+++ b/packages/website/ts/containers/instant.ts
@@ -0,0 +1,30 @@
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { Instant as InstantComponent, InstantProps } from 'ts/pages/instant/instant';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { ScreenWidths } from 'ts/types';
+import { Translate } from 'ts/utils/translate';
+
+interface ConnectedState {
+ translate: Translate;
+ screenWidth: ScreenWidths;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, _ownProps: InstantProps): ConnectedState => ({
+ translate: state.translate,
+ screenWidth: state.screenWidth,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Instant: React.ComponentClass<InstantProps> = connect(mapStateToProps, mapDispatchToProps)(
+ InstantComponent,
+);
diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx
index 2bc8c8849..8c7fef172 100644
--- a/packages/website/ts/index.tsx
+++ b/packages/website/ts/index.tsx
@@ -7,6 +7,7 @@ import { MetaTags } from 'ts/components/meta_tags';
import { About } from 'ts/containers/about';
import { DocsHome } from 'ts/containers/docs_home';
import { FAQ } from 'ts/containers/faq';
+import { Instant } from 'ts/containers/instant';
import { Jobs } from 'ts/containers/jobs';
import { Landing } from 'ts/containers/landing'; // Note(ez): When we're done we omit all old site imports
import { LaunchKit } from 'ts/containers/launch_kit';
@@ -107,6 +108,7 @@ render(
<Route exact={true} path="/" component={Landing as any} />
<Redirect from="/otc" to={`${WebsitePaths.Portal}`} />
<Route path={WebsitePaths.LaunchKit} component={LaunchKit as any} />
+ <Route path={WebsitePaths.Instant} component={Instant as any} />
<Route path={WebsitePaths.Careers} component={Jobs as any} />
<Route path={WebsitePaths.Portal} component={LazyPortal} />
<Route path={WebsitePaths.FAQ} component={FAQ as any} />
diff --git a/packages/website/ts/pages/instant/configurator.tsx b/packages/website/ts/pages/instant/configurator.tsx
new file mode 100644
index 000000000..c836739bb
--- /dev/null
+++ b/packages/website/ts/pages/instant/configurator.tsx
@@ -0,0 +1,12 @@
+import * as React from 'react';
+
+import { Container } from 'ts/components/ui/container';
+import { colors } from 'ts/style/colors';
+
+export interface ConfiguratorProps {
+ hash: string;
+}
+
+export const Configurator = (props: ConfiguratorProps) => (
+ <Container id={props.hash} height="400px" backgroundColor={colors.instantTertiaryBackground} />
+);
diff --git a/packages/website/ts/pages/instant/features.tsx b/packages/website/ts/pages/instant/features.tsx
new file mode 100644
index 000000000..9c1668c1c
--- /dev/null
+++ b/packages/website/ts/pages/instant/features.tsx
@@ -0,0 +1,146 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { Container } from 'ts/components/ui/container';
+import { Image } from 'ts/components/ui/image';
+import { Text } from 'ts/components/ui/text';
+import { colors } from 'ts/style/colors';
+import { ScreenWidths } from 'ts/types';
+import { utils } from 'ts/utils/utils';
+
+export interface FeatureProps {
+ screenWidth: ScreenWidths;
+ onGetStartedClick: () => void;
+}
+
+export const Features = (props: FeatureProps) => {
+ const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
+ const getStartedLinkInfo = {
+ displayText: 'Get started',
+ onClick: props.onGetStartedClick,
+ };
+ const exploreTheDocsLinkInfo = {
+ displayText: 'Explore the docs',
+ linkSrc: `${utils.getCurrentBaseUrl()}/wiki#Get-Started`,
+ };
+ const tokenLinkInfos = isSmallScreen ? [getStartedLinkInfo] : [getStartedLinkInfo, exploreTheDocsLinkInfo];
+ return (
+ <Container backgroundColor={colors.instantSecondaryBackground} className="py3 flex flex-column px3">
+ <FeatureItem
+ imgSrc="images/instant/feature_1.svg"
+ title="Support ERC-20 and ERC-721 tokens"
+ description="Seamlessly integrate token purchasing into your product experience by offering digital assets ranging from in-game items to stablecoins."
+ linkInfos={tokenLinkInfos}
+ screenWidth={props.screenWidth}
+ />
+ <FeatureItem
+ imgSrc="images/instant/feature_2.svg"
+ title="Generate revenue for your business"
+ description="With just a few lines of code, you can earn up to 5% in affiliate fees on every transaction from your crypto wallet or dApp."
+ linkInfos={[
+ {
+ displayText: 'Learn about affiliate fees',
+ linkSrc: `${utils.getCurrentBaseUrl()}/wiki#Learn-About-Affiliate-Fees`,
+ },
+ ]}
+ screenWidth={props.screenWidth}
+ />
+ <FeatureItem
+ imgSrc="images/instant/feature_3.svg"
+ title="Easy and Flexible Integration"
+ description="Use our out-of-the-box design or customize the user interface by integrating the AssetBuyer engine. You can also tap into 0x networked liquidity or choose your own liquidity pool."
+ linkInfos={[
+ {
+ displayText: 'Explore AssetBuyer',
+ linkSrc: `${utils.getCurrentBaseUrl()}/docs/asset-buyer`,
+ },
+ ]}
+ screenWidth={props.screenWidth}
+ />
+ </Container>
+ );
+};
+
+interface LinkInfo {
+ displayText: string;
+ linkSrc?: string;
+ onClick?: () => void;
+}
+
+interface FeatureItemProps {
+ imgSrc: string;
+ title: string;
+ description: string;
+ linkInfos: LinkInfo[];
+ screenWidth: ScreenWidths;
+}
+
+const FeatureItem = (props: FeatureItemProps) => {
+ const { imgSrc, title, description, linkInfos, screenWidth } = props;
+ const isLargeScreen = screenWidth === ScreenWidths.Lg;
+ const maxWidth = isLargeScreen ? '500px' : undefined;
+ const image = (
+ <Container className="center" minWidth="435px" maxHeight="225px">
+ <Image src={imgSrc} additionalStyle={{ filter: 'drop-shadow(0px 4px 4px rgba(0,0,0,.25))' }} />
+ </Container>
+ );
+ const info = (
+ <Container maxWidth={maxWidth}>
+ <Text fontSize="24px" lineHeight="34px" fontColor={colors.white} fontWeight={500}>
+ {title}
+ </Text>
+ <Container marginTop="28px">
+ <Text fontFamily="Roboto Mono" fontSize="14px" lineHeight="2em" fontColor={colors.grey500}>
+ {description}
+ </Text>
+ </Container>
+ <Container className="flex" marginTop="28px">
+ {_.map(linkInfos, linkInfo => {
+ const onClick = (event: React.MouseEvent<HTMLElement>) => {
+ if (!_.isUndefined(linkInfo.onClick)) {
+ linkInfo.onClick();
+ } else if (!_.isUndefined(linkInfo.linkSrc)) {
+ utils.openUrl(linkInfo.linkSrc);
+ }
+ };
+ return (
+ <Container
+ key={linkInfo.linkSrc}
+ className="flex items-center"
+ marginRight="32px"
+ onClick={onClick}
+ cursor="pointer"
+ >
+ <Container>
+ <Text fontSize="16px" fontColor={colors.white}>
+ {linkInfo.displayText}
+ </Text>
+ </Container>
+ <Container paddingTop="1px" paddingLeft="6px">
+ <i
+ className="zmdi zmdi-chevron-right bold"
+ style={{ fontSize: 16, color: colors.white }}
+ />
+ </Container>
+ </Container>
+ );
+ })}
+ </Container>
+ </Container>
+ );
+ return (
+ <Container className="flex flex-column items-center py4 px3">
+ {isLargeScreen ? (
+ <Container className="flex">
+ {image}
+ <Container marginLeft="115px">{info}</Container>
+ </Container>
+ ) : (
+ <Container className="flex flex-column items-center" width="100%">
+ {image}
+ <Container marginTop="48px">{info}</Container>
+ </Container>
+ )}
+ </Container>
+ );
+};
diff --git a/packages/website/ts/pages/instant/instant.tsx b/packages/website/ts/pages/instant/instant.tsx
new file mode 100644
index 000000000..fa6bd1c33
--- /dev/null
+++ b/packages/website/ts/pages/instant/instant.tsx
@@ -0,0 +1,87 @@
+import { utils as sharedUtils } from '@0x/react-shared';
+import * as _ from 'lodash';
+import * as React from 'react';
+import * as DocumentTitle from 'react-document-title';
+
+import { Footer } from 'ts/components/footer';
+import { MetaTags } from 'ts/components/meta_tags';
+import { TopBar } from 'ts/components/top_bar/top_bar';
+import { Container } from 'ts/components/ui/container';
+import { Configurator } from 'ts/pages/instant/configurator';
+import { Features } from 'ts/pages/instant/features';
+import { Introducing0xInstant } from 'ts/pages/instant/introducing_0x_instant';
+import { NeedMore } from 'ts/pages/instant/need_more';
+import { Screenshots } from 'ts/pages/instant/screenshots';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { colors } from 'ts/style/colors';
+import { ScreenWidths } from 'ts/types';
+import { Translate } from 'ts/utils/translate';
+import { utils } from 'ts/utils/utils';
+
+export interface InstantProps {
+ location: Location;
+ translate: Translate;
+ dispatcher: Dispatcher;
+ screenWidth: ScreenWidths;
+}
+
+export interface InstantState {}
+
+const CONFIGURATOR_HASH = 'configure';
+const THROTTLE_TIMEOUT = 100;
+const DOCUMENT_TITLE = '0x Instant';
+const DOCUMENT_DESCRIPTION = '0x Instant';
+
+export class Instant extends React.Component<InstantProps, InstantState> {
+ // TODO: consolidate this small screen scaffolding into one place (its being used in portal and docs as well)
+ private readonly _throttledScreenWidthUpdate: () => void;
+ public constructor(props: InstantProps) {
+ super(props);
+ this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
+ }
+ public componentDidMount(): void {
+ window.addEventListener('resize', this._throttledScreenWidthUpdate);
+ window.scrollTo(0, 0);
+ }
+ public render(): React.ReactNode {
+ return (
+ <Container overflowX="hidden">
+ <MetaTags title={DOCUMENT_TITLE} description={DOCUMENT_DESCRIPTION} />
+ <DocumentTitle title={DOCUMENT_TITLE} />
+ <TopBar
+ blockchainIsLoaded={false}
+ location={this.props.location}
+ style={{ backgroundColor: colors.instantPrimaryBackground, position: 'relative' }}
+ translate={this.props.translate}
+ isNightVersion={true}
+ />
+ <Container backgroundColor={colors.instantPrimaryBackground} />
+ <Introducing0xInstant screenWidth={this.props.screenWidth} onCTAClick={this._onGetStartedClick} />
+ <Screenshots screenWidth={this.props.screenWidth} />
+ <Features screenWidth={this.props.screenWidth} onGetStartedClick={this._onGetStartedClick} />
+ {!this._isSmallScreen() && <Configurator hash={CONFIGURATOR_HASH} />}
+ <NeedMore screenWidth={this.props.screenWidth} />
+ <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} />
+ </Container>
+ );
+ }
+ private readonly _onGetStartedClick = () => {
+ if (this._isSmallScreen()) {
+ utils.openUrl(`${utils.getCurrentBaseUrl()}/wiki#Get-Started`);
+ } else {
+ this._scrollToConfigurator();
+ }
+ };
+ private _isSmallScreen(): boolean {
+ const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
+ return isSmallScreen;
+ }
+ private _scrollToConfigurator(): void {
+ sharedUtils.setUrlHash(CONFIGURATOR_HASH);
+ sharedUtils.scrollToHash(CONFIGURATOR_HASH, '');
+ }
+ private _updateScreenWidth(): void {
+ const newScreenWidth = utils.getScreenWidth();
+ this.props.dispatcher.updateScreenWidth(newScreenWidth);
+ }
+}
diff --git a/packages/website/ts/pages/instant/introducing_0x_instant.tsx b/packages/website/ts/pages/instant/introducing_0x_instant.tsx
new file mode 100644
index 000000000..da3f09faa
--- /dev/null
+++ b/packages/website/ts/pages/instant/introducing_0x_instant.tsx
@@ -0,0 +1,57 @@
+import * as React from 'react';
+
+import { Button } from 'ts/components/ui/button';
+import { Container } from 'ts/components/ui/container';
+import { Text } from 'ts/components/ui/text';
+import { colors } from 'ts/style/colors';
+import { ScreenWidths } from 'ts/types';
+
+export interface Introducing0xInstantProps {
+ screenWidth: ScreenWidths;
+ onCTAClick: () => void;
+}
+
+export const Introducing0xInstant = (props: Introducing0xInstantProps) => {
+ const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
+ const zero = (
+ <Text fontColor={colors.white} fontSize="42px" fontWeight="600" fontFamily="Roboto Mono" Tag="span">
+ 0
+ </Text>
+ );
+ const title = isSmallScreen ? (
+ <div>
+ Introducing<br />
+ {zero}x Instant
+ </div>
+ ) : (
+ <div>Introducing {zero}x Instant</div>
+ );
+ return (
+ <div className="clearfix center lg-pt4 md-pt4" style={{ backgroundColor: colors.instantPrimaryBackground }}>
+ <div className="mx-auto inline-block align-middle py4" style={{ lineHeight: '44px', textAlign: 'center' }}>
+ <Container className="sm-center sm-pt3">
+ <Text fontColor={colors.white} fontSize="42px" lineHeight="52px" fontWeight="600">
+ {title}
+ </Text>
+ </Container>
+ <Container className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 sm-center" maxWidth="600px">
+ <Text fontColor={colors.grey500} fontSize="20px" lineHeight="32px" fontFamily="Roboto Mono">
+ A free and flexible way to offer simple crypto
+ <br /> purchasing in any app or website.
+ </Text>
+ </Container>
+ <div className="py3">
+ <Button
+ type="button"
+ backgroundColor={colors.mediumBlue}
+ fontColor={colors.white}
+ fontSize="18px"
+ onClick={props.onCTAClick}
+ >
+ Get Started
+ </Button>
+ </div>
+ </div>
+ </div>
+ );
+};
diff --git a/packages/website/ts/pages/instant/need_more.tsx b/packages/website/ts/pages/instant/need_more.tsx
new file mode 100644
index 000000000..e6d5c3694
--- /dev/null
+++ b/packages/website/ts/pages/instant/need_more.tsx
@@ -0,0 +1,62 @@
+import * as React from 'react';
+
+import { Button } from 'ts/components/ui/button';
+import { Container } from 'ts/components/ui/container';
+import { Text } from 'ts/components/ui/text';
+import { colors } from 'ts/style/colors';
+import { ScreenWidths } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { utils } from 'ts/utils/utils';
+
+export interface NeedMoreProps {
+ screenWidth: ScreenWidths;
+}
+export const NeedMore = (props: NeedMoreProps) => {
+ const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
+ const backgroundColor = isSmallScreen ? colors.instantTertiaryBackground : colors.instantSecondaryBackground;
+ const className = isSmallScreen ? 'flex flex-column items-center' : 'flex';
+ const marginRight = isSmallScreen ? undefined : '200px';
+ return (
+ <Container className="flex flex-column items-center py4 px3" backgroundColor={backgroundColor}>
+ <Container className={className}>
+ <Container className="sm-center" marginRight={marginRight}>
+ <Text fontColor={colors.white} fontSize="32px" lineHeight="45px">
+ Need more flexibility?
+ </Text>
+ <Text fontColor={colors.grey500} fontSize="18px" lineHeight="27px">
+ View our full documentation or reach out if you have any questions.
+ </Text>
+ </Container>
+ <Container className="py3 flex">
+ <Container marginRight="20px">
+ <Button
+ type="button"
+ backgroundColor={colors.white}
+ fontColor={backgroundColor}
+ fontSize="18px"
+ onClick={onGetInTouchClick}
+ >
+ Get in Touch
+ </Button>
+ </Container>
+ <Button
+ type="button"
+ backgroundColor={colors.mediumBlue}
+ fontColor={colors.white}
+ fontSize="18px"
+ onClick={onDocsClick}
+ >
+ Explore the Docs
+ </Button>
+ </Container>
+ </Container>
+ </Container>
+ );
+};
+
+const onGetInTouchClick = () => {
+ utils.openUrl(constants.URL_ZEROEX_CHAT);
+};
+const onDocsClick = () => {
+ utils.openUrl(`${utils.getCurrentBaseUrl()}/wiki#Get-Started`);
+};
diff --git a/packages/website/ts/pages/instant/screenshots.tsx b/packages/website/ts/pages/instant/screenshots.tsx
new file mode 100644
index 000000000..7dcf17fd1
--- /dev/null
+++ b/packages/website/ts/pages/instant/screenshots.tsx
@@ -0,0 +1,35 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { Container } from 'ts/components/ui/container';
+import { colors } from 'ts/style/colors';
+import { ScreenWidths } from 'ts/types';
+
+export interface ScreenshotsProps {
+ screenWidth: ScreenWidths;
+}
+
+export const Screenshots = (props: ScreenshotsProps) => {
+ const isSmallScreen = props.screenWidth === ScreenWidths.Sm;
+ const images = isSmallScreen
+ ? [
+ 'images/instant/rep_screenshot.png',
+ 'images/instant/dai_screenshot.png',
+ 'images/instant/gods_screenshot.png',
+ ]
+ : [
+ 'images/instant/nmr_screenshot.png',
+ 'images/instant/kitty_screenshot.png',
+ 'images/instant/rep_screenshot.png',
+ 'images/instant/dai_screenshot.png',
+ 'images/instant/gods_screenshot.png',
+ 'images/instant/gnt_screenshot.png',
+ ];
+ return (
+ <Container backgroundColor={colors.instantPrimaryBackground} className="py3 flex justify-center">
+ {_.map(images, image => {
+ return <img className="px1 flex-none" width="300px" height="420px" src={image} key={image} />;
+ })}
+ </Container>
+ );
+};
diff --git a/packages/website/ts/style/colors.ts b/packages/website/ts/style/colors.ts
index 447762969..356d72f7e 100644
--- a/packages/website/ts/style/colors.ts
+++ b/packages/website/ts/style/colors.ts
@@ -21,6 +21,9 @@ const appColors = {
textDarkPrimary: '#000000',
textDarkSecondary: '#5C5C5C',
white: '#fff',
+ instantPrimaryBackground: '#222222',
+ instantSecondaryBackground: '#333333',
+ instantTertiaryBackground: '#444444',
};
export const colors = {
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 89c477085..9c4b8a018 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -353,6 +353,7 @@ export enum WebsitePaths {
FAQ = '/faq',
About = '/about',
LaunchKit = '/launch-kit',
+ Instant = '/instant',
Whitepaper = '/pdfs/0x_white_paper.pdf',
SmartContracts = '/docs/contracts',
Connect = '/docs/connect',
diff --git a/packages/website/tslint.json b/packages/website/tslint.json
index 50f5be4f6..3022b2c84 100644
--- a/packages/website/tslint.json
+++ b/packages/website/tslint.json
@@ -5,6 +5,7 @@
"no-object-literal-type-assertion": false,
"completed-docs": false,
"prefer-function-over-method": false,
- "custom-no-magic-numbers": false
+ "custom-no-magic-numbers": false,
+ "semicolon": [true, "always", "ignore-bound-class-methods"]
}
}